Archives

Archives / 2010 / May
  • WPF ListView as a DataGrid – Part 3

    I have had a lot of great feedback on the blog post about turning the ListView into a DataGrid by creating GridViewColumn objects on the fly. So, in the last 2 parts, I showed a couple of different methods for accomplishing this. Let’s now look at one more and that is use Reflection to extract the properties from a Product, Customer, or Employee object to create the columns. Yes, Reflection is a slower approach, but you could create the columns one time then cache the View object for re-use. Another potential drawback is you may have columns in your object that you do not wish to display on your ListView. But, just because so many people asked, here is how to accomplish this using Reflection.

     WPF ListView

    Figure 1: Use Reflection to create GridViewColumns.

    Using Reflection to gather property names is actually quite simple. First you need to pass any type (Product, Customer, Employee, etc.) to a method like I did in my last two blog posts on this subject. Below is the method that I created in the WPFListViewCommon class that now uses reflection.

    C#
    public static GridView CreateGridViewColumns(Type anyType)
    {
      // Create the GridView
      GridView gv = new GridView();
      GridViewColumn gvc;

      // Get the public properties.
      PropertyInfo[] propInfo =
             anyType.GetProperties(BindingFlags.Public |
                                   BindingFlags.Instance);

      foreach (PropertyInfo item in propInfo)
      {
        gvc = new GridViewColumn();
        gvc.DisplayMemberBinding = new Binding(item.Name);
        gvc.Header = item.Name;
        gvc.Width = Double.NaN;
        gv.Columns.Add(gvc);
      }

      return gv;
    }

    VB.NET
    Public Shared Function CreateGridViewColumns( _
      ByVal anyType As Type) As GridView
      ' Create the GridView
      Dim gv As New GridView()
      Dim gvc As GridViewColumn

      ' Get the public properties.
      Dim propInfo As PropertyInfo() = _
        anyType.GetProperties(BindingFlags.Public Or _
                              BindingFlags.Instance)

      For Each item As PropertyInfo In propInfo
        gvc = New GridViewColumn()
        gvc.DisplayMemberBinding = New Binding(item.Name)
        gvc.Header = item.Name
        gvc.Width = [Double].NaN
        gv.Columns.Add(gvc)
      Next

      Return gv
    End Function

    The key to using Relection is using the GetProperties method on the type you pass in. When you pass in a Product object as Type, you can now use the GetProperties method and specify, via flags, which properties you wish to return. In the code that I wrote, I am just retrieving the Public properties and only those that are Instance properties. I do not want any static/Shared properties or private properties.

    GetProperties returns an array of PropertyInfo objects. You can loop through this array and build your GridViewColumn objects by reading the Name property from the PropertyInfo object.

    Build the Product Screen

    To populate the ListView shown in Figure 1, you might write code like the following:

    C#
    private void CollectionSample()
    {
      Product prod = new Product();

      // Setup the GridView Columns
      lstData.View =
         WPFListViewCommon.CreateGridViewColumns(typeOf(Product));
      lstData.DataContext = prod.GetProducts();
    }

    VB.NET
    Private Sub CollectionSample()
      Dim prod As New Product()

      ' Setup the GridView Columns
      lstData.View = WPFListViewCommon.CreateGridViewColumns( _
           GetType(Product))
      lstData.DataContext = prod.GetProducts()
    End Sub

    All you need to do now is to pass in a Type object from your Product class that you can get by using the typeOf() function in C# or the GetType() function in VB. That’s all there is to it!

    Summary

    There are so many different ways to approach the same problem in programming. That is what makes programming so much fun! In this blog post I showed you how to create ListView columns on the fly using Reflection. This gives you a lot of flexibility without having to write extra code as was done previously.

    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 "WPF ListView as a DataGrid – Part 3" 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".

     

    Read more...

  • Control to Control Binding in WPF/Silverlight

    In the past if you had two controls that you needed to work together, you would have to write code. For example, if you want a label control to display any text a user typed into a text box you would write code to do that. If you want turn off a set of controls when a user checks a check box, you would also have to write code. However, with XAML, these operations become very easy to do.

    Bind Text Box to Text Block

    As a basic example of this functionality, let’s bind a TextBlock control to a TextBox. When the user types into a TextBox the value typed in will show up in the TextBlock control as well.

    To try this out, create a new Silverlight or WPF application in Visual Studio. On the main window or user control type in the following XAML.

    <StackPanel>
      <TextBox Margin="10" x:Name="txtData" />
      <TextBlock Margin="10"
                 Text="{Binding ElementName=txtData,
                                Path=Text}" />
    </StackPanel>

    Now run the application and type into the TextBox control. As you type you will see the data you type also appear in the TextBlock control. The {Binding} markup extension is responsible for this behavior. You set the ElementName attribute of the Binding markup to the name of the control that you wish to bind to. You then set the Path attribute to the name of the property of that control you wish to bind to. That’s all there is to it!

    Bind the IsEnabled Property

    Now let’s apply this concept to something that you might use in a business application. Consider the following two screen shots. The idea is that if the Add Benefits check box is un-checked, then the IsEnabled property of the three “Benefits” check boxes will be set to false (Figure 1). If the Add Benefits check box is checked, then the IsEnabled property of the “Benefits” check boxes will be set to true (Figure 2).

    Figure 1
    Figure 1: Uncheck Add Benefits and the Benefits will be disabled.

    Figure 2
    Figure 2: Check Add Benefits and the Benefits will be enabled.

    To accomplish this, you would write XAML to bind to each of the check boxes in the “Benefits To Add” section to the check box named chkBenefits. Below is a fragment of the XAML code that would be used.

    <CheckBox x:Name="chkBenefits" />

    <CheckBox Content="401k"
              IsEnabled="{Binding ElementName=chkBenefits,
                                  Path=IsChecked}" />

    Since the IsEnabled property is a boolean type and the IsChecked property is also a boolean type, you can bind these two together. If they were different types, or if you needed them to set the IsEnabled property to the inverse of the IsChecked property then you would need to use a ValueConverter class.

    Summary
    Once you understand the basics of data binding in XAML, you can eliminate a lot code. Connecting controls together is as easy as just setting the ElementName and Path properties of the Binding markup extension.

    NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "SL – Basic Control Binding" 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".

    Read more...