Follow @PDSAInc February 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

February 2010 - Posts

Bind ObjectDataProvider Method Parameters in WPF

It is absolutely amazing how much you can do in WPF without writing a line of code. If you take full advantage of the data-binding features in WPF you will find that a lot of the code you used to write to move data from one control to another, or move data from a control on a form and pass it to the method on a class can be completely eliminated!

To illustrate, take a look at Figure 1. This window loads users from your Active Directory, but only loads them once you have typed a letter(s) into the TextBox. This Window has no code behind it at all for loading the users. It uses an ObjectDataProvider to create an instance of a class and call one of its methods. This method takes a single parameter which is the letter(s) of the user name to locate in your active directory. This blog entry will discuss how to build this window and bind the TextBox control to the method parameter of the ObjectDataProvider.

Read AD Users
Figure 1: Retrieve AD Users using an Object Data Provider

Create an AD User Class

First off you need to create a class to hold the data you will retrieve about the user from your Active Directory. Below is a simple class that I created to hold just the Name and the DistinguishedName properties from the user object returned. Feel free to modify this class to return other data.

C#
public class PDSAADUser
{
  public string Name { get; set; }
  public string DistinguishedName { get; set; }
}


Visual Basic 
Public Class PDSAADUser
  Private mName As String
  Private mDistinguishedName As String

  Public Property Name() As String
    Get
      Return mName
    End Get
    Set(ByVal value As String)
      mName = value
    End Set
  End Property

  Public Property DistinguishedName() As String
    Get
      Return mDistinguishedName
    End Get
    Set(ByVal value As String)
      mDistinguishedName = value
    End Set
  End Property
End Class

Create an AD User Collection Class

Next you create a collection class using the Generic List class and creating a list of PDSAADUser objects. In this class is where you create the method to retrieve the list of users from your active directory. Since some companies have many users in their active directory, it is wise to set a property of whether or not to allow all users to be returned. I created a property called AllowAllUsers that I set to false by default so you must pass in at least one letter to the GetUsers method in order to filter the users returned from your active directory. You can initialize this flag to whatever you wish.

Below is a stub of this collection class. You can see the constructor for this class and the AllowAllUsers property and the signature for the GetUsers overloaded method. There are actually two signatures for GetUsers. The first method with only one parameter is the one we are calling from our ObjectDataProvider on this window. It will retrieve the default LDAP Path string from the Active Directory Services built-in to .NET and then pass both that string and the partial name you are searching for to the second GetUsers method. I did this in this sample just to illustrate how to bind a single text box to the ObjectDataProvider. Of course, you could have the ObjectDataProvider call the method with two parameters, you would just have to bind to an LDAP Path string contained in maybe another class that you create. This class could retrieve the LDAP Path from a config file for example.

C#
public class PDSAADUsers : List<PDSAADUser>
{
  public PDSAADUsers()
  {
    AllowAllUsers = false;
  }

  public bool AllowAllUsers { get; set; }

  public PDSAADUsers GetUsers(string partialUserName )
  {
    // Get Default LDAP Path String Here

    // Return users here
  }

  public PDSAADUsers GetUsers(string ldapPath,
                              string partialUserName )
  {
    // Return users here
  }
}

Visual Basic
Public Class PDSAADUsers
  Inherits List(Of PDSAADUser)

  Public Sub New()
    AllowAllUsers = False
  End Sub

  Private mAllowAllUsers As Boolean

  Public Property AllowAllUsers() As Boolean
    Get
      Return mAllowAllUsers
    End Get
    Set(ByVal value As Boolean)
      mAllowAllUsers = value
    End Set
  End Property

  Public Function GetUsers(ByVal partialUserName As String) _
                           As PDSAADUsers
    ' Get Default LDAP Path String Here

    ' Return users here
  End Function
 
  Public Function GetUsers(ByVal ldapPath As String, _
                           ByVal partialUserName As String) _
                           As PDSAADUsers
    ' Return users here
  End Function
End Class

Binding the TextBox to the Object Data Provider

Now, let’s look at how to hook up the TextBox control to the ObjectDataProvider control. First you define the ObjectDataProvider in the <Window.Resources> section of your window as shown below.

<ObjectDataProvider x:Key="ADUsers"
                    ObjectType="{x:Type src:PDSAADUsers}"
                    MethodName="GetUsers">
  <ObjectDataProvider.MethodParameters>
    <x:Static Member="system:String.Empty" />
  </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

Notice that you are having the ObjectDataProvider create an instance of your collection class and call the GetUsers method. Then notice the MethodParameters collection has defined a single parameter. This parameter is defaulted to a string.Empty value.

Now, this is where it gets tricky. What you need to do is to bind the TextBox’s Text property to feed the first parameter of the MethodParameters collection of the ObjectDataProvider. You do this with the following syntax.

<TextBox x:Name="txtPartialName"
         Width="100">
  <TextBox.Text>
    <Binding Source="{StaticResource ADUsers}"
             Path="MethodParameters[0]"
             BindsDirectlyToSource="true"
             UpdateSourceTrigger="PropertyChanged" />
  </TextBox.Text>
</TextBox>

In the <Binding> on the Text property you set the source of the text box to the static resource called ADUsers. This is the key value of the ObjectDataProvider. The Path property is set to the value “MethodParameters[0]”. This tells WPF to bind to the first parameter in the MethodParameters collection. You also need to specify which event will update the MethodParameters collection. In this example the event is when the Text property changes. By firing the PropertyChanged event you are telling the ObjectDataProvider that it should call the method in the MethodName property again and pass in the data that was just passed into the method parameter from the text box.

Summary

You can check out the complete source code to the GetUsers method by downloading the sample (directions below). The GetUser method is just standard active directory retrieval code. The intent of this blog entry was to show you how to perform data-binding between a text box and the method parameters on the ObjectDataProvider. There is no code behind in the WPF Window. The magic of WPF data binding takes care of all the plumbing and calling the methods in your classes. With data binding you can even pass in parameters to those methods from values in your text boxes, or other controls on your windows.

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 " Bind ObjectDataProvider Method Parameters in WPF" 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: Feb 23 2010, 10:25 PM by psheriff | with 7 comment(s)
Filed under: ,
Use XML Files with WPF

XML files are very handy for storing and display data that you might not want to keep in a database. It is wonderful choice for prototyping since you do not need to setup any database tables, connection strings and data objects. Instead you can send a complete project to a user that they can try out immediately without any setup at all. There are actually several methods you can use to display XML within a WPF application, let’s look at a few.

The XML Data
For the samples in this article, the XML data is a simple set of Product data. The XML file, called Product.xml, looks like the following:

<Products>
  <Product>
    <ProductId>1</ProductId>
    <ProductName>Architecting ASP.NET Applications
                 eBook</ProductName>
    <Price>19.95</Price>
  </Product>
  <Product>
    <ProductId>2</ProductId>
    <ProductName>Fundamentals of N-Tier eBook</ProductName>
    <Price>19.95</Price>
  </Product>
     ...
     ...
  <Product>
    <ProductId>3</ProductId>
    <ProductName>Security for ASP.NET Developers
                 eBook</ProductName>
    <Price>19.95</Price>
  </Product>
</Products>

Using the XML Data Provider
The simplest method of display XML data is to use the XmlDataProvider object in XAML. You create an XmLDataProvider and set its Source property to the location of where the XML file is located. Consider the following XmlDataProvider created in a Window.Resources area.

<Window.Resources>
  <XmlDataProvider x:Key="ProductData"
                   Source="/Product.xml"
                   XPath="Products/Product" />
</Window.Resources>

Notice that the Key is set to a unique identifier for this resource. You then specify the Source with where the XML file is located. Finally you specify the top level XPath query that will be used to get to the node level where you will be displaying data. If you use a ListBox on this Window you would specify the ItemsSource to be data bound to this StaticResource “ProductData”. You then reference the element name within the XML that you want to use to display in the ListBox. Since you have already specified “Products/Product” in the XPath attribute of the XmlDataProvider, the DisplayMemberPath can be just set to the element to display; in this case “ProductName”.

<ListBox
   ItemsSource="{Binding
                 Source={StaticResource ProductData}}"
   DisplayMemberPath="ProductName" />

Sorting using a CollectionViewSource
One additional nice feature you might want to add is the ability to sort the XML data. You can accomplish this complete in XAML by using a CollectionViewSource object. The CollectionViewSource object will take a source set of data from an XmlDataProvider (or any data provider for that matter) and you can then apply some additional elements to do things like sorting or grouping. For sorting data you will add SortDescriptions to the collection. Look at the XAML below.

<Window.Resources>
  <XmlDataProvider x:Key="ProductData"
                   Source="/Product.xml"
                   XPath="Products/Product" />
  <CollectionViewSource x:Key="collProducts"
                        Source="{StaticResource ProductData}">
    <CollectionViewSource.SortDescriptions>
      <scm:SortDescription PropertyName="ProductName"
                           Direction="Ascending" />
    </CollectionViewSource.SortDescriptions>
  </CollectionViewSource>
</Window.Resources>

You can see that you added a CollectionViewSource.SortDescriptions element within the <CollectionViewSource> element. This element allows you to add one or many sort description objects. The SortDescription object you add comes from the System.ComponentModel namespace within the WindowsBase assembly. So, you will need to add a XAML namespace at the top of your window that looks like the following:

xmlns:scm=
 "clr-namespace:System.ComponentModel;assembly=WindowsBase"

You can give it any “name” you want, I chose “scm”, so that is what I used when adding the SortDescription element with the PropertyName set to “ProductName” and the Direction set to “Ascending”. Setting these two properties is what will then sort the data in the CollectionViewSource by the ProductName element in the XML file. Notice that the Source property of the CollectionViewSource is set to the XmlDataProvider object. So the CollectionViewSource creates a collection of the XML data and applies to the sort description to create a new “view” of the original data. You now use the CollectionViewSource as the ItemsSource property of the List Box as shown below.

<ListBox
  ItemsSource="{Binding Source={StaticResource collProducts}}"
  DisplayMemberPath="ProductName" />

Using LINQ to XML
Another method you can use to display XML data in a WPF application is to use LINQ to XML. Sometimes LINQ to XML might be necessary if you have a more complicated XML file, or if you wish to filter the data in a special way, or just want to read a few elements instead of every element.
To use LINQ to XML you must set the Build Action property of the Product.xml file to “Content” and the Copy to Output Directory to “Copy if newer”. Instead of using an XmlDataProvider this time load the data writing some C# or VB code. In the ListBox you set the ItemsSource to “{Binding}”. This tells the list box that the data will be supplied at runtime.

<ListBox Margin="10"
         ItemsSource="{Binding}"
         Name="lstProducts" />

In the Windows Loaded event you will call the ProductsLoad procedure which uses LINQ to XML to create a collection of XElement objects.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
  ProductsLoad();
}

To use LINQ to XML you will need to import a couple of namespaces.

using System.Linq;
using System.Xml.Linq;

Now, in the ProductsLoad procedure you use the Load method of the XElement class to load the XML file. Then you write a normal LINQ query to iterate over the “Product” Descendants in the XML file. In this query you will also use an order by clause to order each element by ProductName, then select the ProductName. You could select more elements if you want, but since all you are doing is displaying ProductName in the ListBox, let’s just grab this one piece of data from the XML file.

private void ProductsLoad()
{
  var xElem = XElement.Load(@"Product.xml");

  var products = from prod in xElem.Descendants("Product")
           orderby prod.Element("ProductName").Value
           select prod.Element("ProductName").Value;

  lstProducts.DataContext = products;
}

Summary
XML files are a great way to display data in WPF applications. I find XML files to be especially useful for prototyping as I find creating XML files much quicker than creating database tables and hooking up to those database tables from WPF. You have a lot of different methods to retrieve the XML data. In this article I showed you how to display the data using the XmlDataProvider, a CollectionViewSource and LINQ to XML.

NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "Use XML Files in WPF" 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: Feb 01 2010, 02:18 PM by psheriff | with 1 comment(s)
Filed under: ,
More Posts