Follow @PDSAInc August 2010 - Posts - Paul Sheriff's Blog for the Real World

Paul Sheriff's Blog for the Real World

This blog is to share my tips and tricks garnered over 25+ years in the IT industry

Paul's Favorites

August 2010 - Posts

Change Templates Dynamically in Silverlight

Silverlight has the flexibility to modify the look of your controls dynamically at runtime with just a few lines of code. Take a look at Figures 1 and 2 and you will see two different views of the same list box and data. To accomplish this, you simply need to setup two different resources of XAML code that you can switch between at runtime.

More Detail 
Figure 1: More detail

Less Detail 
Figure 2: Less detail

The Product Class

For this example, I will be using a simple Product class with four properties, and a list of Product objects using the Generic List class. Create a Product class as shown in the following code:

public class Product {
  #region Constructors

  public Product(){ }

  public Product(int id, string name, string type, decimal price)
  {
    this.ProductId = id;
    this.ProductName = name;
    this.ProductType = type;
    this.Price = price;
  }
  #endregion

  public int ProductId { get; set; }
  public string ProductName { get; set; }
  public string ProductType { get; set; }
  public decimal Price { get; set; }
}

Next, create a Product collection class that will create a mock set of product objects and fill in a property called DataCollection with this mock set of products.

public class Products : List<Product>
{
  public Products()
  {
    BuildCollection();
  }

  public ObservableCollection<Product> DataCollection { get; set; }
   
  public ObservableCollection<Product> BuildCollection()
  {
    DataCollection = new ObservableCollection<Product>();

    DataCollection.Add(new Product(1,
       "Haystack Code Generator for .NET", "Product", 799));
    DataCollection.Add(new Product(4,
       "Fundamentals of N-Tier eBook", "Book", 20));

    ... // More data here

    DataCollection.Add(new Product(10,
       "PDSA .NET Productivity Framework", "Product", 2500));

    return DataCollection;
  }
}

The Silverlight Page

To create this Silverlight page, you will need to layout a couple of different areas. First you need a top part where the two buttons are located, then you need a ListBox below that. A Grid is ideal for laying out this type of scenario. Below is the XAML for the <Grid> portion of this page.

<Grid x:Name="LayoutRoot"
      Background="White">
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
  <StackPanel Grid.Row="0"
              Margin="10"
              Orientation="Horizontal">
    <Button Name="btnMore"
            Margin="5"
            Tag="tmplMore"
            Content="More"
            Click="ChangeTemplate" />
    <Button Name="btnLess"
            Margin="5"
            Tag="tmplLess"
            Content="Less"
            Click="ChangeTemplate" />
  </StackPanel>
  <ListBox Margin="10"
            Grid.Row="1"
            Name="lstData"
            ItemTemplate="{StaticResource tmplMore}"
            ItemsSource="{Binding
                        Source={StaticResource productCollection},
                        Path=DataCollection}" />
</Grid>

Create an Instance of Products in your XAML

You need to have your XAML user control create an instance of your Products class. You can do that in XAML by first adding a namespace to your <UserControl> element that references the assembly in which your Products class is located.

xmlns:data="clr-namespace:Silverlight_Data"

Next, you add a <UserControl.Resources> section and create the instance of the products class from the Silverlight_Data namespace referenced by the local XAML namespace that you called "data".

<UserControl.Resources>
  <data:Products x:Key="productCollection" />
</UserControl.Resources>

The XAML above creates an instance of the Products class and assigns it the key name of "productCollection". If you look at the <ListBox> element declared earlier you see that this key name is used in the ItemsSource binding.

Create the XAML Templates

The next items that add to the <UserControl.Resources> section of the XAML are the <DataTemplates>. There are two data templates created as resources in this user control. One has a key of "tmplMore" and one has a key of "tmplLess". Below is the XAML used to create the list box that looks like Figure 1.

<DataTemplate x:Key="tmplMore">
  <StackPanel Orientation="Vertical"
              HorizontalAlignment="Left"
              Margin="8">
    <TextBlock FontSize="16"
                Text="{Binding Path=ProductName}" />
    <StackPanel Orientation="Horizontal">
      <TextBlock FontSize="12"
                  Margin="0,0,4,0"
                  Text="Type: " />
      <TextBlock FontSize="12"
                  Text="{Binding Path=ProductType}" />
      <TextBlock FontSize="12"
                  Margin="20,0,4,0"
                  Text="Price: " />
      <TextBlock FontSize="12"
                  Text="{Binding Path=Price, StringFormat=c}" />
    </StackPanel>
  </StackPanel>
</DataTemplate>

The next data template in the UserControl.Resources section has the key of "tmplLess". This template is used to create the page shown in Figure 2. The XAML to create this page looks like the following:

<DataTemplate x:Key="tmplLess">
  <StackPanel Orientation="Horizontal">
    <TextBlock FontSize="16"
                Text="{Binding Path=ProductName}" />
  </StackPanel>
</DataTemplate>

Notice that the "tmplMore" data template is assigned to the ListBox as a default in the XAML listed above. However, this is just so you have something to look at in design mode. You can modify this template dynamically at runtime. Let’s now look at how to accomplish that.

Switch XAML Templates at Runtime

You write code to respond to each button’s click event. The same event procedure is used for each button. Notice the Tag property is set to the key name of the data template you created in the UserControl.Resources section.

<Button Name="btnMore"
        Margin="5"
        Tag="tmplMore"
        Content="More"
        Click="ChangeTemplate" />
<Button Name="btnLess"
        Margin="5"
        Tag="tmplLess"
        Content="Less"
        Click="ChangeTemplate" />

Now, let’s look at the ChangeTemplate() event procedure that is called by each of these button’s Click events.

C#

private void ChangeTemplate(object sender, RoutedEventArgs e)
{
  DataTemplate dt;

  dt = (DataTemplate)this.Resources[
      ((Button)sender).Tag.ToString()];

  lstData.ItemTemplate = dt;
}


VB.NET
Private Sub ChangeTemplate(ByVal sender As System.Object, _
 ByVal e As System.Windows.RoutedEventArgs) _
  Handles btnMore.Click, btnLess.Click
  Dim dt As DataTemplate

  dt = CType(Me.Resources( _
        CType(sender, Button).Tag.ToString()),  _
          DataTemplate)

  lstData.ItemTemplate = dt
End Sub

Using the Resources property of the UserControl class you can locate the resource with the name you pass to the indexed property. The name you pass is the Tag property of the button that fired this event. One thing to note is that you should include error handling within this code because if the FindResource method does not find the resource, then it will throw an exception. I purposely left out the exception handling code for brevity in this example.

Summary

That is all there is to it. If you run this sample you will dynamically switch between the two templates at runtime. You simply create as many XAML templates as you want that will allow your user to switch between different views of the same list box. Give each template a unique name, and then write a little code to find each of the resources at runtime. Once you have located the appropriate resource, you assign it to the ItemTemplate property of the list box and Silverlight will change the look of the control instantly.

NOTE: You can download the complete sample code (in both VB and C#) at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then " Change Templates Dynamically in Silverlight" from the drop-down.

Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".

Filtering CollectionView Data in Silverlight 4

If you are using Silverlight's ListBox control, you can filter the data in a CollectionViewSource object using just a little bit of simple code. For this example, I will be using a simple Product class with two properties, and a list of Product objects using the Generic List class. Try this out by creating a Product class as shown in the following code:

public class Product {
  public Product(int id, string name) {
    ProductId = id;
    ProductName = name;
  }

  public int ProductId { get; set; }
  public string ProductName { get; set; }
}

Create a collection class that initializes a property called DataCollection with some sample data as shown in the code below:

public class Products : List<Product>
{
  public Products()
  {
    InitCollection();
  }

  public List<Product> DataCollection { get; set; }

  List<Product> InitCollection()
  {
    DataCollection = new List<Product>();

  DataCollection.Add(new Product(1, "PDSA Framework"));
  DataCollection.Add(new Product(2, "Haystack"));
  DataCollection.Add(new Product(3, "Fundamentals of .NET eBook"));
  DataCollection.Add(new Product(4, "WPF Fundamentals Video"));
  DataCollection.Add(new Product(5, "Fundamentals of ASP.NET Security eBook"));
  DataCollection.Add(new Product(6, "Fundamentals of SQL Server eBook"));
  DataCollection.Add(new Product(7, "Microsoft VS.NET 2010"));
  DataCollection.Add(new Product(8, "Microsoft Silverlight 4"));

    return DataCollection;
  }
}

The screen shot shown in Figure 1 is a Silverlight page that allows the user to filter the Product data by typing in a value into the text box, then clicking on the Search button.

Filtering Data (Fig. 1)

Figure 1: Filter Collection Data in Silverlight

If the user fills in a partial product name, such as the letter 'F' and then clicks on the Search button, the results are as shown in Figure 2.

 Figure 2

Figure 2: The data filtered in Silverlight

You next need to add an XML namespace to your MainPage.xaml so you can reference the Products class.

xmlns:local="clr-namespace:SLFilterData"

The 'local' namespace is the name of the project that you created (in my case 'SLFilterData'). Create a UserControl.Resources section in your Silverlight page that looks like the following:

<UserControl.Resources>
  <local:Products x:Key="products" />
  <CollectionViewSource x:Key="prodCollection"
                        Source="{Binding Source={StaticResource products},
                             Path=DataCollection}">
  </CollectionViewSource>
</UserControl.Resources>

The first line of code in the resources section creates an instance of your Products class. The constructor of the Products class calls the InitCollection method which creates the various Product objects and adds them to the DataCollection property of the Products class. Once the Products object is instantiated you now add a CollectionViewSource object in XAML using the Products object as the source of the data to this collection. A CollectionViewSource allows us to perform sorting, grouping and filtering on our collection of Product objects.

Next, you create the search area using a StackPanel, TextBlock, TextBox and a Button control:

<StackPanel Orientation="Horizontal"
            Margin="10"
            Grid.Row="0">
  <TextBlock Text="Enter Partial Name: " />
  <TextBox Width="100"
            Name="txtName" />
  <Button Name="btnSearch"
          Content="Search"
          Click="btnSearch_Click" />
</StackPanel>

Now add a list box to your XAML page and set the DisplayMemberProperty to be "ProductName" which is the property on the Product class that you wish to display in the list box.

<ListBox Margin="10"
          Grid.Row="1"
          Name="lstData"
          DisplayMemberPath="ProductName"
          ItemsSource="{Binding Source={StaticResource collProducts}}" />

Now you can write the code behind for the click event of the Seach button. In the Click event call a method name FilterData that will perform the filtering using CollectionViewSource.

private void FilterData()
{
  if (lstData != null)
  {
    ICollectionView dataView = default(ICollectionView);

    dataView = (ICollectionView)lstData.ItemsSource;

    dataView.Filter = prod => ((Product)prod).ProductName.ToLower()
                                 .StartsWith(txtName.Text.ToLower());

    lstData.ItemsSource = dataView;
  }
}

In the FilterData method you create an ICollectView object from the existing ItemsSource property of the list box. When you use a CollectionViewSource object in your XAML, the data is put in the collection as an object that implements the ICollectionView interface. You can then set the Filter property of the collection view to a predicate that will determine the filter on the data. After this is set, you give this new ICollectionView object to the ItemsSource property of the list box and the filter is applied. The new data is then displayed in the list box.

Summary
That's all there is to it. A simple way to allow your users to filter data from a collection with just a few lines of code!

NOTE: You can download the complete sample C# and XAML code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "Filtering CollectionView Data in Silverlight 4" from the drop-down.

Good Luck with your Coding,
Paul Sheriff

** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".

 

Posted: Aug 03 2010, 12:24 PM by psheriff | with 8 comment(s)
Filed under: ,
More Posts