Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Conditional Controls at Runtime in Silverlight DataGrid

0.00/5 (No votes)
9 Aug 2011 1  
Conditional controls at Runtime in Silverlight DataGrid

Introduction

Most of the business applications implement Datagrid in Silverlight and each of the scenarios comes with its own complication that sometimes looks funny but challenging. I am writing this article after getting stuck with a similar situation. In this post, we will discuss about approaches available to bind various controls, to different cells of a particular column inside Datagrid, using IValueconvertor and with a bit of common-sense applied.

The Issue/Scenario

Our application required few records to be displayed over grid... simplest thing we can do even while sleeping. But the challenge lies in displaying different set of controls based on business rules. Let me clarify with an example.

We have a set of Customer lists that need to be displayed over Grid. The Customer object holds a property called Mood, either the mood can be Happy, Neutral or Angry. Well, it doesn't stop here. If the Mood is not available, the Cell must display "NA" and if the property is null, then it should display a HyperLinkbutton which in turn will send a request to the particular customer seeking for feedback. The prototype for a particular control can be seen below:

SNAGHTMLcefdd2_thumb1.png

So the grid must be smart enough either to use Image control or Simple Text Block control with NA or a Button control with its own code behind logic. The binding data of each row will decide the control for a particular column at run time. My next section will focus on different approaches and some basic concepts of grid customization.

Addressing the Issue and Some Basics of DataGrid

The Datagrid comes up with a variety of Column types, which can be one of:

  1. DataGridTextColumn: for plain Text Values
  2. DataGridCheckBoxColumn: for Boolean Values
  3. DataGridTemplateColumn: for Integrated Controls (Bound Controls)

A brief about these column types and their scenarios of use is nicely described over here. Once we choose our custom ColumnType, we can use any control as a cell template that will hold the binding data. To use custom columns, we should force Datagrid to stop auto generating columns, instead we can define our columns and assign properties as binding. The figure below shows a datagrid with custom columns.

image_thumb2.png

The DataGridTemplateColumn is handy to show custom column content with bound control for editing. By default, it supports use of a uniform control across column cells. That means once defined, all the cells of that column will be uniform. As I mentioned earlier, CellTemplete property of DataGrid allows us to display data while that cell is not in editing mode.

SNAGHTML3846440_thumb3.png

Here in this post, we will concentrate on displaying the data so our focus will be on CellTemplete.

While looking for a solution for the issue mentioned above, we thought of various options such as Dynamic DataTemplate (DataTemplateSelector) which WPF support but not Silverlight. DataTemplateSelector allows to use specific template based on the data object logic. Then, I thought of modifying XAML at runtime by creating Datatemplate at code behind and attaching it to cell template although we kept it as the last choice.We were looking for a control which can hold any control defined at runtime and the choice of control can be decided using Ivalueconvertor based on the particular business object.

What about ContentControl? Basically ContentControl is a control whose Control property can be any of the Silverlight UIElement.

So the best appeared solution for the given scenario is to use ContentControl inside DataTemplate and assign the required custom control at runtime using IvalueConvertor. We will look into the implementation over the next section.

Setting up the Grid and Binding

The page contains a Grid which will show the Customer data.The Customer business entity object is somehow defined as mentioned below:

namespace GridInSilverlight 
{ 
  public  enum Mood
    {
        NA,
        Satisfied,
        Normal,
        UnSatisfied,
        UA
    }
  
    public class Customer
   {
        public string Name{get;set;}
        public string Place { get; set; }
        public string  Phone{get;set;}
        public bool IsCorporate{get;set;}
        public Mood CustomerMood { get; set; }
    }
}

and the Grid definition for the above entity is as follows:

<sdk:DataGrid AutoGenerateColumns="False" 
                      Height="253"
                      Margin="12,45,0,0"
                      Name="dgCustomers"
                      VerticalAlignment="Top"
                      HorizontalAlignment="Left"
                      Width="462">
    <sdk:DataGrid.Columns>
        <sdk:DataGridTextColumn CanUserReorder="True"
                                   CanUserResize="True"
                                   CanUserSort="True"
                                   Width="Auto" 
                                   Binding="{Binding Name}" Header="Name"/>
        <sdk:DataGridTextColumn CanUserReorder="True"
                                   CanUserResize="True"
                                   CanUserSort="True"
                                   Width="Auto"
                                   Binding="{Binding Place}"
                                   Header="Country" />
        <sdk:DataGridTextColumn CanUserReorder="True"
                                   CanUserResize="True"
                                   CanUserSort="True"
                                   Width="Auto"
                                   Binding="{Binding Phone}"
                                   Header="Phone" />
        <sdk:DataGridCheckBoxColumn 
                                   Width="Auto"
                                   Binding="{Binding IsCorporate}"
                                   Header="Is Corporate" />
        <sdk:DataGridTemplateColumn CanUserReorder="True"
                                   CanUserResize="True"
                                   CanUserSort="True"
                                   Width="Auto"  Header="Mood">
            <sdk:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ContentControl Content=
				"{Binding Converter={StaticResource MoodConv },
			         ConverterParameter='CUS'}"
                                    HorizontalContentAlignment="Stretch"
                                    VerticalContentAlignment="Stretch" /> 
                        </DataTemplate>
                        
            </sdk:DataGridTemplateColumn.CellTemplate>
        </sdk:DataGridTemplateColumn>
        <sdk:DataGridTemplateColumn CanUserReorder="True"
                                    CanUserResize="True"
                                    CanUserSort="True"
                                    Width="Auto"
                                    Header="Company Mood">
            <sdk:DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <ContentControl Content="{Binding Converter=
				{StaticResource MoodConv },ConverterParameter='COM'}"
                                     HorizontalContentAlignment="Stretch"
                                     VerticalContentAlignment="Stretch" />
                </DataTemplate>
            </sdk:DataGridTemplateColumn.CellTemplate>
        </sdk:DataGridTemplateColumn>
    </sdk:DataGrid.Columns>
</sdk:DataGrid>  

Consider the last column:

SNAGHTML3846440_thumb4.png

The Convertor here is added as a resource in the control and that is going to define the UIElement that will in turn will be used to display the values. The next step is to create a convertor for Mood display. Convertors are methods that allows you to modify the data as the control goes through the binding process.The convertor method inherits from IValueConvertor and implements Convert and ConvertBack methods for modifying Source to Target and vice versa. More details on this topic can be found here.

The Convertor code for this particular project is:

public class MoodConvertor:IValueConverter
   {
       #region IValueConverter Members
 
       public object Convert(object value, Type targetType, 
		object parameter, System.Globalization.CultureInfo culture)
       { 
           Customer cusObj = value as Customer;
           Image img = new Image();
           switch (cusObj.CustomerMood)
           { 
               case Mood.Normal:
 
                       img.Source = new System.Windows.Media.Imaging.BitmapImage
					(new Uri("Normal.png", UriKind.Relative));
                   return img;
 
               case Mood.Satisfied:
 
                   img.Source = new System.Windows.Media.Imaging.BitmapImage
				(new Uri("Satisfied.png", UriKind.Relative));
                   return img;
 
               case Mood.UnSatisfied:
                   img.Source = new System.Windows.Media.Imaging.BitmapImage
				(new Uri("UnSatisfied.png", UriKind.Relative));
                   return img;
 
               case Mood.UA:
                   HyperlinkButton btn = new HyperlinkButton();
                   btn.Content = "Invite Suggestion";
                   return btn;
 
               default :
                   TextBlock tbU = new TextBlock();
                   tbU.Text = "-";
                   return tbU;
           } 
       }
 
       public object ConvertBack(object value, Type targetType, 
		object parameter, System.Globalization.CultureInfo culture)
       {
           throw new NotImplementedException();
       }
 
       #endregion
   } 

Few lines of code generate Dummy customer data, for your case it can be data from your service call. On compiling the project, the Grid is exactly what we needed:

Dynamic Control for DataGrid

Last Few Words…

The above work is one of the examples of DataGrid customization. The CellTemplete along with DataGridTemplateColumn can be used for further customization. Hope this post will help you in understanding the Grid concepts and customization concepts. The flexibility that Silverlight offers is amazing and XAML is certainly eligible for centre of Microsoft Focus. Let me know your views Be right back.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here