Taoffi's blog

prisonniers du temps

Choices in a logical tree view – WPF sample

Using check boxes in TreeView control is a handy way for presenting choices in their logical tree-like structure.

In real life, though, choices can be a mix of inclusive (check-box) and exclusive (radio-button) options.

I expose here a solution for using that mix of option types in one same tree view.

The problem

The problem is divided into three main subjects:

  • How to use a mix of checkbox / radio button nodes in the same tree view control
  • How to get a radio button to be toggled from checked to unchecked status: Checkboxes are, 'naturally', able to be toggled from checked to unchecked status. This is not the case for Radio buttons. The result is that when you use radio button in a tree view, you will be able to check it but not to get it uncheck!
  • How to handle exclusive choices selection. That is when an exclusive option gets selected (checked), for instance,we must unselect all other exclusive sibling options.

 

To solve the first question, we will use:

  • A tree node object which indicates its option type (exclusive / inclusive)
  • Hierarchical control templates for each choice type
  • A template selector which will select the correct template according to the node object choice type

 

To solve the second, we will simply create a new Toggled Radio Button (which derives from RadioButton) and get this new object handle the Click event to toggle its selection status.

 

 

public class RadioToggleButton : RadioButton
{
    protected override void OnClick()
    {
        IsChecked = !IsChecked;
    }
}

 

 

The third question will be solved by implementing the required behaviors within our special tree node object.

 

The TreeNode object

The TreeNode object exposes few properties:

  • A Title
  • A Parent node (TreeNode)
  • A list of Children (List of TreeNode items)
  • A boolean flag which indicates if the node represents an exclusive choice option
  • A boolean flag which indicates if the node is selected

Through these properties, TreeNode object can expose other properties like its Root node, the First exclusive parent or descendant… etc.

 

The TreeNode Hierarchical data template

 

<UserControl.Resources>
…
…
    <!-- hierarchical template for checkbox treeview items -->
    <HierarchicalDataTemplate x:Key="checkBoxTemplate" 
        DataType="{x:Type app:TreeNode}"
        ItemsSource="{Binding Children}">
        <StackPanel Orientation="Horizontal">
            <CheckBox Focusable="False"
                VerticalAlignment="Center"
                IsChecked="{Binding IsSelected, Mode=TwoWay}" />
            <TextBlock Text="{Binding Title}" />
        </StackPanel>
    </HierarchicalDataTemplate>
 
    <!-- hierarchical template for (toggled) radio buttons treeview items -->
    <HierarchicalDataTemplate x:Key="radioButtonTemplate" 
            DataType="{x:Type app:TreeNode}"
            ItemsSource="{Binding Children}">
        <StackPanel Orientation="Horizontal">
            <ctrl:RadioToggleButton Focusable="False"
            VerticalAlignment="Center"
            IsChecked="{Binding IsSelected, Mode=TwoWay}" />
            <TextBlock Text="{Binding Title}" Margin="4, 1, 0, 0" />
        </StackPanel>
    </HierarchicalDataTemplate>
</UserControl.Resources>

 

 

The TreeView node's Item template selector

 

public class TreeNodeXTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(
                object item, DependencyObject container)
    {
        FrameworkElement    element = container    as FrameworkElement;
        TreeNode    node    = item  as TreeNode;
 
        if (element != null && node != null)
        {
            if (node.IsExclusive)
                return element.FindResource("radioButtonTemplate")
                                 as HierarchicalDataTemplate;
            return element.FindResource("checkBoxTemplate")
                                as HierarchicalDataTemplate;
        }
        return null;
    }
}

 

 

We can now use an ItemTemplateSelector to tell the Tree view control to select the adequate data template for each item according the tree node choice selection type (exclusive / inclusive)

 

<UserControl.Resources>
    <app:TreeNodeXTemplateSelector	x:Key="templateSelector" />
    …
    …
</UserControl.Resources>

 

<TreeView x:Name="treeview1" ItemsSource="{Binding Root.Children}"
                  ItemTemplateSelector="{StaticResource templateSelector}"/>

 

 

Exclusive node selection behavior

TreeNode selection behavior can be summarized as follows:

  • If the node is inclusive: do nothing (just set the selected flag)
  • If the node is exclusive (and selected):
    • Unselect all exclusive siblings (siblings = Parent's Children)
    • Select all inclusive child nodes
    • Select the first exclusive child node if any

 

public void UpdateSelection()
{
    if(! _isExclusive)
        return;
 
    if(_isSelected == true)
    {
        UnSelectSiblings();
    }
 
    SelectChildren(_isSelected);
}

 

 

 

protected void SelectChildren(bool selected)
{
    if(! selected)
    {
        UnSelectChildren();
        return;
    }
 
    TreeNode firstEx = FirstExclusiveChild;
 
    if(firstEx != null)
        firstEx.IsSelected = selected;
 
    foreach(TreeNode node in _children)
    {
        if(node.IsExclusive)
            continue;
 
        node.SetSelection(value: selected, updateChildren: true);
    }
}

 

 

Sample screenshot

 

Download the sample code TreeViewRadioAndCheckButtons.zip (67.88 kb)

Throw, but only ‘exceptional’ exceptions!

I find the Try/Catch mechanism fascinating! This is probably due to some events I lived in the (not so far) History! (see below)

The thing is, when I see any of its related keywords: try, catch, finally and, specially, throw… I feel some kind of nervousness or unease!

Unfortunately, for me, more and more source code tries, catches and throws exceptions. It seems sometimes easier to throw an exception while simply an object ‘status’ would be required.

Some history

I remember an intriguing piece of code (2 or 3 C language macros) that was one of the first research I encountered about implementing a dynamic error capturing (now called ‘exception handling’). I kept this code for years (in my ‘code-museum’!) but ended up by losing it through the long journey of OS, compilers and IDEs changes!

Fortunately, I found someone (Francesco Nidito) who still (beautifully) talks about this nearly same macros (you can have a more detailed look here). His article is exactly about the solution that I first saw in the 80s, with some interesting additions (mixed with a good dose of humorJ).

 

If you used C language before, you know the impact (and importance) of ‘preprocessing’. This is the step where the compiler expands the expressions before going further in the compilation process.

For example, if you define a macro:

 

#define SAY_HELLO   int    x;\

                    for( x = 0; x < 10; x++)\

                           printf(“Hello!”);

 

In the preprocessing step, the compiler will replace each SAY_HELLO occurrence by the lines of code above.

 

longjmp And setjmp

Before diving in the historical macros, to better understand their work, we should first have a look at those two (strange) C language functions: longjmp and setjmp (declared in setjmp.h header file):

 

int setjmp(jmp_buf env);

void longjmp(jmp_buf env, int val);

 

The documentation says:

 

The setjmp function saves a stack environment, which you can subsequently restore, using longjmp. When used together, setjmp and longjmp provide a way to execute a non-local goto. They are typically used to pass execution control to error-handling or recovery code in a previously called routine without using the normal calling or return conventions.

A call to setjmp saves the current stack environment in env. A subsequent call to longjmp restores the saved environment and returns control to the point just after the corresponding setjmp call. All variables (except register variables) accessible to the routine receiving control contain the values they had when longjmp was called.

It is not possible to use setjmp to jump from native to managed code.

Note   setjmp and longjmp do not support C++ object semantics. In C++ programs, use the C++ exception-handling mechanism.

The basic Try/Catch macros

Using the magic that can be done by setjmp and longjmp, the following bizarre macros are the basis of a try/catch mechanism:

 

#define TRY            do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){

#define CATCH          } else {

#define ETRY           } }     while(0)

#define THROW          longjmp(ex_buf__, 1)

 

So, now you may write

 

TRY

{

       DoSomething(“with this string”);

}

CATCH

{

       printf(“some error happened!”);

}

ETRY         /* end of try/catch! */

 

At compile-time, this would be expanded to the following code:

 

do{ jmp_buf ex_buf__; if( !setjmp(ex_buf__) ){

{

       DoSomething(“with this string”);

}

} else {

{

       printf(“some error happened!”);

}

} }   while(0)           /* end of try/catch! */

 

 

What does it mean?

Let’s try to read the macros meaning:

TRY, ends with an ETRY. That is do{ xxxx } while(0) (which means: do xxxx only ONCE)

TRY starts by saving the current caller’s stack into a ‘jmp_buf’ variable. If saving the current caller stack succeeds, the next instructions (code block of ‘try’) are executed. Otherwise, the catch block instructions are executed instead.

THROW executes a non-local GOTO (by calling longjmp) which returns execution to the previous caller of the stack saved into the jmp_buf with a return value of 1 (of course, longjmp can be called with a different return value).

 

Anything new?

Of course, our C++, C# and VB Try/Catch mechanism is a little more elaborate than the one exposed here. The foundations remain the same. And, in fact, nothing had fundamentally changed in this area since: any try/catch block executes, at least, this fearful acrobatic setjmp / longjmp.

 

It may be useful to remember this before writing your next try/catch block!

 

Organize your MSDN Help Favorites

If you regularly use MSDN help (Visual Studio Documentation or MSSQL Server Books OnLine (BOL)) you may have noticed that it is not possible to sort or search the list of help favorites.

Migrating these favorites to another machine is almost more painful!

I suffered from these problems for a long time, until I decided to write a tool to help resolving these lacks.

What does the tool do?

HelpFavoriteOrganizer can locate and read your Favorites (xml) file (for Visual Studio or MSSQL documentation) and allow you to sort and search favorite topics. It also locates duplicated topics (i.e. topic having the same help addresses)

You can then save you favorite file, to either a new xml file or overwriting the original XML favorite file.

Another useful feature is to import (merge) an existing xml favorite file into your favorite topics. This can allow an easier roaming life, and can also be used to share your help favorites with someone else.

 

ATTENTION: be careful when deleting items or overwriting files because this tool DOES NOT ask any confirmation. (i.e. use it at your own risk!)

That said (!), you can download it Here: HelpFavoritesOrganizer.zip (34.82 kb)

Some screen captures

Try to locate and load either VStudio help or SQL help favorites

 

 

 

 

.

Sort / Search your topics… items highlighted

Save the list either to a new file or to the original help favorites file.

 

.

Locate / delete duplicated topics (As you can see, I have no more duplicatesJ)

 

.

Import (merge) another favorites xml file

 

Silverlight database to DataGrid, yet another approach- Part V

The data record (the ‘form’)

As I mentioned in Part II, my proposed solution (aimed to transfer and communicate data between a Silverlight Client and the database server) is composed of the following schematic classes:

Data level classes

SilverDataTable

Represents the table (or view, or function…) data.

Contains:

A meta-data table

A list of data rows

SilverDataRow

Represents one record of data.

Contains:

List of data cells

Linked to:

A parent table

SilverDataCell

Represents one record’s data cell.

Linked to:

A parent row

A parent meta-data column

Meta-data level classes

SilverMetaTable

Represents the table’s meta-data (schema)

Contains:

A list of meta-data columns

Linked to:

A parent table

SilverMetaColumn

Represents one column’s schema information.

Note: This is the ‘Key Class’ where you can insert all your required business logic.

Linked to:

A parent meta-data table

 

The SilverMetaColumn class is the key class which will transport many of business logic information from the database server to the client (and back to the server).

A meta-data column object of this class can transport information like:

§  The column’s data type;

§  Can the column contain null value?

§  The semantic type of the field (ex: control type… i.e. is this an option list? a value entry field?…)

§  Valid value ranges;

§ 

§  etc.

 

What I want to expose here is: how to use this meta-data column object to ‘automatically’ (or semi-automatically) compose a data record (form) on the client side.

 

From the field semantic àto the control àto the form

After having examined many of the data entry forms in various contexts, I think that a data entry (from the user interface point of view) is either:

§  A value entry control (i.e. a TextBox or TextBox-like: Numeric Up-down control for example)

§  Or a choice control (i.e. a ListBox, ComboBox, CheckBox, Radio-buttons-collection or other type of collection container controls)

 

Of course, the visual aspect of the control and its interactivity scenario may vary… but its presentation-semantic remains the same: a value entry or a choice.

From the business logic point of view (at the server side), what is important is not the visual aspect or visual transitions for presenting and collecting the data. What is important is the conformance of the collected data to specific business logic constraints:

§  Does the entry conform to the required data type?

§  Does the entry conform to the required valid range?

§ 

 

According to this approach, we can imagine a solution where the server tells the client:

§  Here is the requested data record composed of:

§  Column 1 : this is the record key column, It is Read-only (i.e. it will be handled at the server)

§  Column 2: this is an entry of data type Text, Required (cannot be null), cannot exceed 50 characters, Current value is “sample entry”;

§  Column 3: this is an entry of data type integer, Can be null, Valid range is 0 through 40, Default is 25, Current value is 32;

§  Column 4: this a single choice of the following option list (x1, x2, x3), Cannot be null, Current value is x2;

§  Column 5: this a boolean value, default is True, Current value is False;

§ 

 

Receiving this information, the client can then undertake the presentation process, for example:

§  Start record presentation transition (animation);

§  For each column, create the corresponding control (ex: according to the user interface graphical chart);

§  Set each control’s properties to conform to business constraints (read-only, max chars, valid values check… etc.)

 

Here is an example of a solution using this approach:

 

Silverlight database to DataGrid, yet another approach- Part IV

Filtering database data

As we have seen in Part III, the SQL Select statement is composed of the following parts:

SELECT                 [field1], [field2],… [fieldn]

FROM                   [database table or ‘table-like’ store]

WHERE                [conditions]

ORDER BY           [field name] <sort direction>,

                               [field name] <sort direction>

 

It is the ‘WHERE’ clause of the SQL statement that is used to filter the data.

‘WHERE’ is followed by ‘conditions’. Several conditions are concatenated using AND or OR operator.

What is a filter condition?

A ‘condition item’ can be presented as:

[Field name] [Comparison operator] [Filter value]

 

A collection of ‘condition items’ can be presented as something like:

<Condition item> <Concatenation operator> <Other condition item>

 

Examples:

Name = ‘John’

Amount >= 100

(Last_name LIKE ‘%bama’) AND (Age >= 20)

 

That seems easy to be represented by an object:

public class SilverFiltertItem

{

       string              m_field_name,

                           m_filter_value;

       CompareOperator     m_compare_operator  = CompareOperator.EQUAL;

       ConcatOperator      m_concat_operator   = ConcatOperator.AND;

       ...

       ...

The concatenation and comparison operators are members of the following enum types:

public enum filter_concat_operator

{

       and,

       or,

       none

};

 

public enum filter_compare_operator

{

       Equal,

       Not_equal,

       Like,

 

       GreatertThan,

       GreatertThanOrEqual,

       LessThan,

       LessThanOrEqual

       ...

       ...

};

 

Two properties can give us the Compare and Concatenate strings when required:

protected string ConcatString

{

       get

       {

             if( m_concat_opertaor == filter_concat_operator.none)

                    return "";

 

             // return ‘AND’ or ‘OR’

             return Enum.GetName( typeof( filter_concat_operator), m_concat_opertaor).ToUpper();

       }

}

 

protected string CompareString

{

       get

       {

             switch (m_compare_operator)

             {

                    case filter_compare_operator.Equal:

                           return "=";

 

                    case filter_compare_operator.Like:

                           return " Like ";

 

                    case filter_compare_operator.Not_equal:

                           return "!=";

 

                    case filter_compare_operator.GreatertThan:

                           return ">";

 

                    case filter_compare_operator.GreatertThanOrEqual:

                           return ">=";

 

                    case filter_compare_operator.LessThan:

                           return "<";

 

                    case filter_compare_operator.LessThanOrEqual:

                           return "<=";

 

                    default:

                           throw new Exception("Unknown Compare opertor encoutered!");

             }

       }

}

 

The FilterItem object can now provide us with its SQL string through a property like the following:

public string SqlFilterString

{

       get

       {

             if( string.IsNullOrEmpty(m_filter_value)

                           || string.IsNullOrEmpty( m_target_column_name))

                    return "";

 

             string       field_name   = "[" + m_target_column_name + "]",

                          str_ret      = ConcatString + "(";

 

             string str_value    = m_filter_value;

            

             str_ret      += field_name + " " + CompareString + " " + str_value + ") ";

             return str_ret;

       }

 

A filter collection class may look like this:

public class SilverFilter : List<SilverFilterItem>

{

       ...

       ...

 

The filter collection can return the entire SQL filter string through successive calls to its member items:

public string SqlFilterString

{

       get

       {

             if( Count <= 0)

                    return "";

 

             int    ndx          = 0;

             string str_ret      = "";

 

             foreach (SilverFilterItem f in this)

             {

                    if (ndx <= 0)

                           f.Concat_operator = filter_concat_operator.none;

                    else

                    {

                           if( f.Concat_operator == filter_concat_operator.none)

                                  f.Concat_operator   = filter_concat_operator.and;

                    }

 

                    str_ret      += f.SqlFilterString;

                    ndx++;

             }

 

             return str_ret;

       }

 

 

Our DataTable object (see previous posts) can now include a Filter collection object and construct the SQL Where clause:

 

protected SilverFilter    m_filter     = new SilverFilter();

...

...

 

public string SqlCommand

{

       get

       {

             ...

             ...

             string       str_cmd      = "SELECT * FROM " + m_table_name;

             string       str_sort     = m_sort.StrSql;

             string       str_filter   = m_filter.SqlFilterString;

 

             if( ! string.IsNullOrEmpty( str_filter))

                    str_cmd      += " WHERE(" + str_filter + ")";

 

             if( ! string.IsNullOrEmpty( str_sort))

                    str_cmd      += " ORDER BY " + str_sort;

 

             return str_cmd;

       }

 

Note: a better approach would, of course, be to map the filter field names to the table’s meta-data table fields… or directly use MetaDataTable’s columns as filter members (instead of using field names as strings). In this last case, we would be able to check columns’ data types and also act more closely to database’s business logic.

 

In other words: what is proposed here is a simple approach that can evolve according to your needs.

 

 

You can download the sample code: SilverDbDataGrid-2-sorting&filtering.zip (1.87 mb)

Silverlight database to DataGrid, yet another approach- Part III

Sorting and filtering database records

After having succeeded to display our server data into Silverlight DataGrid (see previous post), we will now continue the adventure to complete our solution with some useful and necessary features that Silverlight DataGrid originally proposes (for example, sorting records) and add some new features for filtering records.

 

Silverlight DataGrid allows the user to sort displayed rows by clicking into column headers.

That is nice and helpful. But, in the context of data provided by a server through a database, that doesn’t seem to be quite a correct approach.

In fact, in such context, if you click to sort a column in the ascending order, the displayed data records may not contain the entire values stored in the database. The data should be ‘refreshed’ to represent the effective sorted values according to currently stored database data in its entirety.

 

Sorting database data

How database data can be sorted?

The answer: this can be done using the SQL ‘ORDER BY’ clause.

We use SQL to query the data according to the following (simplified) statement template:

SELECT                [field1], [field2],… [fieldn]

FROM                  [database table or ‘table-like’ store]

WHERE                [conditions]

ORDER BY           [field name] <sort direction>,

                            [field name] <sort direction>

 

The ORDER BY part, contains a list of field names (each of which should be one of the listed SELECT fields, or, at least, one of the queried table or ‘table-like’ fields)

Each field in the ORDER BY clause can have a specified sort direction (ASC for ascending, or DESC for descending). The default being the ascending direction (if the direction is omitted)

 

If we have to represent an ‘order by’ item as an object, the object may then be something like this:

public class SortItem

{

       string       m_field_name;

       SortDirection m_direction  = SortDirection.ASC;

       ...

       ...

 

So, in our case, we can simply sort our DataGrid by building a list (List<SortItem>) of clicked column names (met-data column names) and passing them to the server to compose the ORDER BY part of the query accordingly and return too us the desired sorted data.

 

Implementing the solution

Let’s begin, at the server side, by enriching our service’s SilverDataTable (see Part II) object by a new SortList object, which will simply be a List<> of SortItem.

 

public enum sort_direction

{

       asc,

       desc,

       none

};

 

A SortItem object can be defined as follows:

 

[DataContract]

public class SilverSortItem

{

       protected string           m_target_column_name       = "";

       protected sort_direction   m_sort_direction    = sort_direction.asc;

       ...

       ...

 

We can now define a sort-list object which is mainly a List<SilverSortItem > that takes care for some constraints like, for example, not adding duplicate fields:

 

public class SilverSort : List<SilverSortItem>

{

 

The class exposes an indexer that returns the field by its name:

public SilverSortItem this[string field_name]

{

       get

       {

             if( string.IsNullOrEmpty( field_name) || Count <= 0)

                    return null;

 

             foreach (SilverSortItem e in this)

             {

                    if( string.Compare( e.Target_column_name, field_name, true) == 0)

                           return e;

             }

             return null;

       }

 

An Add method, to add or modify settings of an existing sort field:

public new void Add(SilverSortItem element)

{

       if( element == null || string.IsNullOrEmpty( element.Target_column_name))

             return;

 

       SilverSortItem      e      = this[element.Target_column_name];

 

       if( e == null)

             base.Add( element);

       else

             e.CopyOther( element);

}

 

And a property that returns the SQL sort string of the contained fields:

public string StrSql

{

       get

       {

             if (Count <= 0)

                    return "";

 

             string str_ret = "";

 

             foreach (SilverSortItem s in this)

             {

                    if( str_ret.Length > 0)

                           str_ret      += ", ";

 

                    str_ret += s.StrSql;

             }

             return str_ret;

       }

}

 

Let’s now include a Sort list into our SilverDataTable class:

[DataContract]

public class SilverDataTable

{

       protected SilverSort       m_sort = new SilverSort();

 

 

We can now extend our SqlCommand property to include the sort string:

string str_sort     = m_sort.StrSql;

 

if( string.IsNullOrEmpty( str_sort))

       return "SELECT * FROM " + m_table_name;

return "SELECT * FROM " + m_table_name + " ORDER BY " + str_sort;

 

We will also change our WCF service method to include an optional list of sort field names:

 

[OperationContract]

public SilverDataTable GetData(string str_connet_string,

                           string str_sql_command,

                           SilverSort sort_items,

                           int n_records)

 

 

Sorting… the Client-side job

At the client-side, our DataGrid should send us a message each time a column should be added to the SilverDataTable sort list. And, unfortunately, that is not as ‘intuitive’ as we may like!

Manish Dalal published a very interesting paper about custom sorting and paging inside a DataGrid. His work presents a good (and extensible) start point.

The usable part of his work in our project is the CollectionView class which can give us more control on sorting in response to DataGrid Column Click events.

As you may see at Bea Stollnitz interesting blog, Silverlight DataGrid internally uses a CollectionViewSource (an object that implements ICollectionView interface).

That is: When we set DataGrid’s ItemsSource to an observable collection, it integrates it into its own ICollectionView object.

Fortunately, the DataGrid is smart enough to let us implement this object ourselves, i.e. if we set its ItemsSource to an object that implements the ICollectionView, the DataGrid will use this instead of its own one.

So, let’s create a class that implements the ICollectionView:

public class SilverCollectionView<T> : ObservableCollection<T>, ICollectionView

{

 

The ICollectionView exposes a collection of ‘SortDescriptions’ that we will use, for the requirements of our project, as a list of field names to be sorted. i.e. each time a column will be clicked, we will add the column name to the SortDescriptions list and generate a Refresh event to request the server’s data sorted as desired.

Here is the SilverDatasetView helper class that will integrate our SilverDataTable as an ICollectionView:

public class SilverDatasetView : SilverCollectionView<SilverDataRow>

{

       public SilverDatasetView() : base()

       {

       }

 

       public SilverDatasetView(SilverDataTable service_data_table) : base()

       {

             CopyDataset( service_data_table);

       }

 

       public bool CopyDataset(SilverDataTable data_table)

       {

             if( data_table == null || data_table.Rows == null)

                    return false;

 

             base.SourceCollection      = data_table.Rows;

             return true;

       }

 

Once we receive the data from our database server, we can now set the DataGrid’s ItemsSource to a SilverDatasetView object:

SilverDatasetView   dataset_view = new SilverDatasetView(m_table.Rows);

data_grid.ItemsSource                   = dataset_view;

 

To tell the DataGridColumn how to send us desired sort items, we will set its SortMemberPath to the data column name:

Grid_col.CanUserSort              = true;

Grid_col.SortMemberPath    = data_col.Name;

 

The last part is to respond to the Refresh event of our SilverDatasetView in order to collect the desired sort field names and request the data accordingly:

dataset_view.OnRefresh     += new EventHandler<RefreshEventArgs>(m_dataset_view_OnRefresh);

 

void m_dataset_view_OnRefresh(object sender, RefreshEventArgs e)

{

       if( m_sort_fields == null)

             m_sort_fields = new ObservableCollection<SilverSortItem>();

 

       m_sort_fields.Clear();

 

       SilverSortItem      sort_element;

 

       foreach (SortDescription s in e.SortDescriptions)

       {

             sort_element = new SilverSortItem();

             sort_element.Target_column_name   = s.PropertyName;

             sort_element.Sort_direction             =

                           (s.Direction == ListSortDirection.Ascending)

                           ?(sort_direction.asc)

                           :(sort_direction.desc);

 

             m_sort_fields.Add( sort_element);

       }

      

       RequestSilverDataset();

}

 

RequestSilverDataset() method will, mainly, do the following:

DataServiceClient   cli    = service_helpers.DataServiceProxy(5);

 

cli.GetDataCompleted += new EventHandler<GetDataCompletedEventArgs>(cli_GetDataCompleted);

cli.GetDataAsync( str_connet_string, str_sql_command, m_sort_fields, n_records);

 

That is it… your DataGrid can now be sorted according to the real data on the server.

Don’t forget: Click the column to sort/ shift + click to add the column to the sorted list…

 

Download the sample code:

SilverDbDataGrid-2-sorting.zip (1.36 mb)

Scrollable ComboBox

I am working on a new Silverlight user interface version of Simplesite.net and, as anyone can imagine, that involves a good dive into Silverlight as a ‘Line Of Business’ application technology.

One of the problems I encountered was to make the Combo box control able to respond to Mouse Wheel messages.

After having searched on different blogs and web sites, I didn’t find a suitable solution and ended up by delving into the subject.

Some of the proposed solutions consisted in ‘bringing into view’ one of the combo box items to force the list to scroll up or down as required… that seemed a little bit like a good workaround but was not very efficient and had a bad visual aspect.

 

What is a Silverlight ComboBox?

One of the nice (and pedagogic) aspects in Expression Blend is to be able to edit any existent control template (right click the control, select Edit Template / Edit a copy).

 

 

In Expression Blend, a Control Template reveals all the components of the control… this helps to understand some of the internal mechanisms of the control and how to use them efficiently.

 

To know more about the ComboBox control, I used Blend to insert one somewhere, and selected to edit a copy of its template.

That revealed the main components of the control:

§ A Layout Grid, containing:

§ A border (content presenter border) containing the static part of the combobox;

§ A Popup containing a ScrollViewer which will display the items.

 

It now seems clear that the scroll problem should be handled at the ScrollViewer component.

 

The SetIsMouseWheelScrollingEnabled method of the ScrollViewer can simply be used to activate the Mouse Wheel message handling for this component.

 

The solution

I saved my template to the application resources (App.xaml) with x:key=”combo_box_template”

<!-- ************* scrollable combo box template *******************************-->

<ControlTemplate x:Key="combo_box_template" TargetType="ComboBox">

 

 

I then created a class named ScrollableComboBox deriving from ComboBox

The control template is loaded and applied at class’s instantiation… and Mouse Wheel handling activated on the corresponding ScrollViewer component.

 

 

public partial class ScrollableComboBox : ComboBox

{

       protected ScrollViewer            m_scroll_viewer            = null;

 

       public ScrollableComboBox()

       {

             this.Style   = (Style) App.Current.Resources["ScrollableComboBoxStyle"];

             this.Template = (ControlTemplate) App.Current.Resources["combo_box_template"];

             this.ApplyTemplate();

            

             m_scroll_viewer = (ScrollViewer)GetTemplateChild("ScrollViewer");

 

             if (m_scroll_viewer != null)

             {

                    m_scroll_viewer.SetIsMouseWheelScrollingEnabled(true);

             }

    }

 

 

Surprisingly, that is all we need to activate scrolling on a Silverlight ComboBox!

We can now insert a ScrollableComboBox anywhere we need.

 

Animating Silverlight control inside the HTML Page

Live demo

.

 

 

A Silverlight control can communicate and interact with other HTML elements of the page on which it is placed.

This is done by using the HtmlPage object (namespace System.Windows.Browser)

 

By using HtmlPage, you can have access to all HTML elements of the current page and be able to get and set many of their properties and attributes, and, accessorily, call DHTML script functions that may be located there.

This means, among other things, that you can get and set style attributes of the HTML element inside which your own Silverlight control is hosted (the DIV element having the id commonly named "silverlightControlHost")

 

<div id="silverlightControlHost"

       ...

 

This gave me an idea about creating a custom control which would represent this same hosting html DIV element and, through this custom control, interact with the hosting element properties (width, height, location… etc.)

One of the nice features of Silverlight is the Storyboard animations usually used to animate Silverlight controls.

So, what if we try to use a storyboard to animate the Silverlight hosting html element!

 

Suppose that our animation should move the html host element across the page. From an html viewpoint, this would mean to change its top/left coordinates.

A Silverlight user control doesn’t contain Top / Left properties required to do such a job. So we have to add those properties to our custom control.

 

I first created an (empty) custom user control:

 

Xaml:

<UserControl x:Class="SilverHtmlInteraction.HostingDivControl"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

       Background="Transparent"

       SizeChanged="UserControl_SizeChanged"

    Width="200" Height="200">

    <Grid x:Name="LayoutRoot" Background="White">

 

    </Grid>

</UserControl>

 

The control members:

 

private HtmlElement m_div        = null;

 

public HtmlElement Div

{

       get { return m_div; }

       set { m_div = value; }

}

 

The new Left and Top properties

 

public double Left

{

       get { return attrib = GetDimension("left", "offsetLeft", 0.0); }

       set { SetDimentionAttribute("left", value); }

}

public double Top

{

       get { return attrib = GetDimension("top", "offsetTop", 0.0); }

       set { SetDimentionAttribute("top", value); }

}

 

 

How to obtain html element dimensions (width, height, left, top... etc.)

 

// get the html element’s dimension (example: width, height, left...)

// first try to find the dimension in the element’s style (width, height, left, top...)

// if not found, try to obtain the element’s dimension property (offsetWidth, offsetHeight...)

private double GetDimension(string attrib_name, string property_name, double default_value)

{

       double attrib = GetDimensionAttribute(attrib_name, default_value);

 

       // if the style attribute is not present, try to get the dimension property

       if (attrib <= 0.0)

             return GetDimensionProperty( property_name, default_value);

       return attrib;

}

 

// get the html element’s style attribute (example: width, height, left...)

protected double GetDimensionAttribute(string attrib_name, double default_value)

{

       if (m_div == null)

       {

             debug_display_div_error();

             return default_value;

       }

 

       // try to get the style attribute’s value

       string str_value = m_div.GetStyleAttribute(attrib_name);

 

       if (string.IsNullOrEmpty(str_value))

       {

             return default_value;

       }

       // remove the dimension's unit (px)

       str_value = str_value.Replace("px", "");

 

       double value = default_value;

 

       // try to convert to numeric value

       if (double.TryParse(str_value, out value) == false)

             return default_value;

       return value;

}

 

// get the html element’s dimension property (example: offsetHeight, offsetWidth...)

protected double GetDimensionProperty(string property_name, double default_value)

{

       if( m_div == null)

       {

             debug_display_div_error();

             return default_value;

       }

      

       string str_value    = m_div.GetProperty( property_name).ToString();

 

       if (string.IsNullOrEmpty(str_value))

       {

             return default_value;

       }

       double value = default_value;

 

       // try to convert to numeric value

       if (double.TryParse(str_value, out value) == false)

             return default_value;

 

       return value;

}

 

I then registered the new Left and Top properties with the dependency system:

 

public static DependencyProperty LeftProperty = DependencyProperty.Register(

                    "Left", typeof(double), typeof(HostingDivControl),

                    new PropertyMetadata(

                           new PropertyChangedCallback(LeftPropertyChanged) ));

 

public static DependencyProperty TopProperty = DependencyProperty.Register(

                    "Top", typeof(double), typeof(HostingDivControl),

                    new PropertyMetadata(

                           new PropertyChangedCallback(TopPropertyChanged)));

 

private static void LeftPropertyChanged(DependencyObject obj,

                           DependencyPropertyChangedEventArgs e)

{

       if (obj == null)

             return;

       if (obj is HostingDivControl != true)

             return;

 

       HostingDivControl ctrl = (HostingDivControl)obj;

 

       ctrl.Left    = (double)e.NewValue;

}

 

 

private static void TopPropertyChanged(DependencyObject obj,

                           DependencyPropertyChangedEventArgs e)

{

       if( obj == null)

             return;

       if( obj is HostingDivControl !=true)

             return;

 

       HostingDivControl   ctrl   = (HostingDivControl) obj;

 

       ctrl.Top     = (double) e.NewValue;

}

 

 

The html element accessor should do some work each time this member is changed:

 

public HtmlElement Div

{

       get { return m_div; }

       set

       {

             m_div = value;

 

             if (m_div != null)

             {

                    base.Width   = this.Width;

                    base.Height  = this.Height;

                    Left         = GetDimension("left", "offsetLeft", 0.0);

                    Top          = GetDimension("top", "offsetTop", 0.0);

 

                    // to be able to change the left and top propertites,

                    // the html element should have its position style set

                    // to relative or absolute.

                    If (string.IsNullOrEmpty( m_div.GetStyleAttribute("position")))

                           m_div.SetStyleAttribute("position", "relative");

             }

             else

                    m_div_id = "";

       }

}

 

 

We are now ready to use our new custom control to animate the Silverlight control inside its hosting html page.

 

<Grid x:Name="LayoutRoot" Background="Transparent">

       <local:HostingDivControl x:Name="host_div" Margin="0"/>

 

The animation Storyboard

Let’s create a storyboard that changes the top/left properties of our control (which is the silver light control itself)

Note: I couldn’t use Expression Blend to create the storyboard. Blend seemed confused about the properties to be animated for this ‘special’ control. So I ended up by creating the storyboard by hand!

 

<UserControl.Resources>

       <Storyboard x:Name="Storyboard1">

             <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"

             Storyboard.TargetName="host_div" Storyboard.TargetProperty="(Top)">

                    <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>

                    <EasingDoubleKeyFrame KeyTime="00:00:00.50" Value="50"/>

                    <EasingDoubleKeyFrame KeyTime="00:00:00.80" Value="85"/>

                    <EasingDoubleKeyFrame KeyTime="00:00:01.00" Value="130"/>

             </DoubleAnimationUsingKeyFrames>

 

             <DoubleAnimationUsingKeyFrames BeginTime="00:00:00"

             Storyboard.TargetName="host_div" Storyboard.TargetProperty="(Left)">

                    <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>

                    <EasingDoubleKeyFrame KeyTime="00:00:00.50" Value="100"/>

                    <EasingDoubleKeyFrame KeyTime="00:00:00.80" Value="225"/>

                    <EasingDoubleKeyFrame KeyTime="00:00:01.00" Value="350"/>

             </DoubleAnimationUsingKeyFrames>

                    ...

                    ...

 

       </Storyboard>

</UserControl.Resources>

 

 

Live demo

 

Download the sample code

AnimatedSilverHtmlHost.zip (83.45 kb)

 

Revealing object properties

System Attributes can be used to simply tag and retrieve object properties and methods in particular context.

In my case here, I wanted to be able to know which properties are contained in objects in order to be able to dynamically assign or change their values using simple text entries in a database.

 

I created an (empty) Attribute and named it xSysPropertyAttribute:

 

[global::System.AttributeUsage(

             AttributeTargets.Property,

             Inherited = false,

             AllowMultiple = true)]

public sealed class xSysPropertyAttribute : Attribute

{

       public xSysPropertyAttribute()

       {

       }

}

 

I then used this attribute to ‘tag’ the desired objects’ properties:

 

[xSysProperty]

public bool BoolProperty

{

       get { return m_bool_property; }

       set { m_bool_property = value; }

}

 

[xSysProperty]

public string StringProperty

{

       get { return m_string_property; }

       set { m_string_property = value; }

}

 

Using System.Reflection, I, now, can retrieve these properties and dynamically list them:

 

foreach (PropertyInfo p in obj.GetType().GetProperties())

{

       bool   has_sys_attribute   = Attribute.IsDefined( p, typeof(xSysProperty), false);

 

       if(has_sys_attribute)

       {

             // Do something with this property

       }

}

 

We can use this simple code to dynamically build lists of object’s (tagged) properties.

Once the list of the desired properties has been built, we can now read and modify their values (using user input, xml, text files or database records):

 

Example of Read the property’s value:

 

public object GetValue(MyObject obj, string property_name)

{

       if( obj == null || string.IsNullOrEmpty( property_name))

             return null;

 

       PropertyInfo pinfo  = this[property_name];

 

       if( pinfo == null)

             return null;

       return pinfo.GetValue(obj, null);

}

 

Example of Set the property’s value:

 

public bool SetValue(MyObject obj, string property_name, object value)

{

       if( obj == null)

             return false;

      

       PropertyInfo pinfo  = this[property_name];

 

       if(pinfo == null)

             return false;

 

       // is this a readonly property?

       if(pinfo.CanWrite == false)

             return false;

 

       // get the property's data type

       Type   property_type = pinfo.PropertyType;

       object new_value;

 

       try

       {

             // try to convert the given value to property's data type

             new_value    = Convert.ChangeType( value, property_type);

       }

       catch (Exception)

       {

             return false;

       }

 

       try

       {

             // try to assign the converted value to the object

             pinfo.SetValue( obj, new_value, null);

       }

       catch (Exception)

       {

             return false;

       }

 

       return true;

}

 

Still we have another problem: we need a solid link between listed properties and the objects on which we may get and set properties’ values. i.e. we need to be sure that a property is actually part of the target object without having to check this each time a get or set is requested.

Here comes one the benefits of template classes.

We can implement our pattern using a template list like the following:

 

public class xBuiltinPropertiesListBase<PROPERTY, OBJ_TYPE, PROPERTY_SYS_ATTRIB>

             : List<PROPERTY> where PROPERTY : PropertyInfo

 

The code above defines a list template that will contain objects of type PROPERTY and that type should be a PropertyInfo (or one derived class)

It also defines that for the list to be initialized, a class (System.Type) OBJ_TYPE and a System Attribute PROPERTY_SYS_ATTRIB should be provided.

 

This way, our list explicitly integrates the Type on which it will operate.

Providing the System Attribute may also allow extending the list template for future use in other contexts.

 

On list initialization, the template will proceed to listing all properties with the attribute PROPERTY_SYS_ATTRIB defined within the class of OBJ_TYPE:

 

public bool LoadClassAttributeProperties()

{

       Clear();

 

       Type   obj_type     = typeof(OBJ_TYPE);

 

       // loop through all class's properties.

       // insert those properties defined with the specified System.Attribute.

       foreach (PropertyInfo p in obj_type.GetProperties())

       {

             // Does this property define our System.Attribute?. add it to the list.

             bool   has_sys_attribute = Attribute.IsDefined( p,

                                        typeof( PROPERTY_SYS_ATTRIB), false);

 

             if(has_sys_attribute)

             {

                    PROPERTY     new_property = (PROPERTY)p;

                    Add(new_property);

             }

       }

 

       return true;

}

 

 

The above GetValue and SetValue methods will also have to be slightly modified before being integrated in the list template. Example:

 

public bool SetValue(OBJ_TYPE obj, string property_name, object value)

{

       if( obj == null)

             return false;

      

       PROPERTY     my_property  = this[property_name];

 

       if( my_property == null)

             return false;

 

       // is this a readonly property?

       if( my_property.CanWrite == false)

             return false;

 

       // get the property's data type

       Type   property_type = my_property.PropertyType;

       object new_value;

       ...

       ...

 

 


Download the sample code ExtensibleObjectProperties.zip (46.35 kb)

 

 

Invoking methods by name. A first approach

As many developers know, one of the interesting namespaces in .NET is System.Reflection.

Here I try to use Reflection to invoke loaded assemblies’ methods by their names. This can be quite useful for applications like storing menu or button actions in a database and bringing them to life during runtime (I will post something about this subject shortly).

The attached test application demonstrates this in a very simple manner. Each dialog button invokes a method defined somewhere in the loaded assembly using its name. The search is done by few methods in MethodFinder static class.

 

The dialog displays 3 buttons. The OnClick handler for each button invokes a method by its name:

private void button1_Click(object sender, EventArgs e)

{

       invoke_method("Method1");

}

 

private void button2_Click(object sender, EventArgs e)

{

       invoke_method("Method2");

}

 

The invoke_method function, calls a method finder to retrieve the method and, if found, invokes it:

 

private void invoke_method(string method_name)

{

       MethodInfo          method       = MethodFinder.FindMethod(method_name);

       string              str_result   = "";

 

       if (method != null)

       {

             str_result = method.Invoke(this, null).ToString();

             MessageBox.Show(str_result);

       }

       else

             MessageBox.Show("Couldn't find method in loaded assemblies");

}

 

What you should know

You probably know that a .NET assembly is composed of modules (generally just one module), each module is composed of classes (Types) and each class is composed of fields, properties and methods.

The MethodFinder.FindMethod function loops through runtime loaded assemblies, modules and classes to search for the method and return the found method if any.

 

FindMethod function:

public static MethodInfo FindMethod( string method_name)

{

       foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())

       {

             method = FindAssemblyMethod( asm, method_name);

             if( method != null)

                    return method;

       }

       return null;

}

 

FindAssemblyMethod function loops through assembly’s classes:

public static MethodInfo FindAssemblyMethod(Assembly asm, string method_name)

{

       MethodInfo   method;

 

       foreach (Module module in asm.GetModules())

       {

             method = FindModuleMethod( module, method_name);

             if( method != null)

                    return method;

       }

       return null;

}

 

As you have already guessed, FindModuleMethod function loops through module’s classes to search the method:

public static MethodInfo FindModuleMethod(Module module, string method_name)

{

       Type[]       module_types;

       MethodInfo   method;

 

       module_types = module.GetTypes();

 

       foreach (Type module_class in module_types)

       {

             method = FindClassMethod( module_class, method_name);

             if( method != null)

                    return method;

       }

 

       return null;

}

 

Finally FindClassMethod searches for the method inside the class’s available methods:

public static MethodInfo FindClassMethod( Type module_class, string method_name)

{

       MethodInfo[] methods;

 

       methods = module_class.GetMethods();

       foreach (MethodInfo method in methods)

       {

             if( string.Compare( method.Name, method_name, true) == 0)

                    return method;

       }

 

       return null;

}

 

This is a first approach that I believe that many useful applications can be built on.

I will expose some ideas on the subject in a next post.

 

Download the sample code (with some more details inside) InvokeMethodByName.zip (30.31 kb)