Posts for Category: Data Binding

Silverlight 2.0 beta1 and WPF Data Binding – what’s the same and what’s different?

Silverlight 2.0 promises to bring much of the goodness of WPF to the browser. So how does one of my favourite WPF features - data binding - fare in the new Silverlight 2.0 beta 1 world? To help answer this question I drew up the following summary:

Similarities Differences
Binding Object – the Binding object is present in both SL 2.0 and WPF. Many simple binding scenarios will probably work between the two without modification, but if you’re using the more complex properties of the Binding object in WPF you’ll need to revisit that for Silverlight 2.0 code. The INotifyPropertyChanged interface is also used for change notifications on data objects to be propagated back up to the binding infrastructure. Binding Object – although the Binding object exists in SL 2.0 and WPF the SL 2.0 version is very pared-back compared to WPF, having only 5 properties: Converter, ConverterCulture, ConverterParameter, Mode and Source, in contrast to the 20 or so relevant properties the WPF binding object exposes or inherits from its base types. One of the most key properties on the WPF binding object – the path isn’t even a property at all on the Silverlight equivalent. Instead it is specified as a constructor property. Also the Path in SL 2 can’t drill down into indexes or attached properties the way it can in WPF, however you can still access sub-properties on objects. Josh has some screen-shots from Reflector showing the difference in size of the two types.
Data Context – the concept of a Data Context for a control which is propagated from a parent control down to child controls is shared between WPF and Silverlight 2 beta 1. As with WPF the FrameworkElement type adds the DataContext property in Silverlight 2.0 beta 1. Binding Markup Extension – although syntactically quite similar (albeit with less properties) bindings in Silverlight are quite different internally to their WPF counterparts because they don’t use a managed Binding Markup Extension. In fact, from what we can see of Silverlight 2.0 beta 1 there ARE no markup extensions of any kind. The Silverlight documentation discusses them here but they don’t appear anywhere in the object model. Presumably the implementations of the various markup extensions are hard-wired into the Silverlight runtime.
Converters – One of my favourite extensibility points of WPF has been completely migrated to Silverlight 2.0 beta 1 (possibly due to the simplicity of the IValueConverter interface). A converter and converter parameter can be supplied as part of a binding. Binding to Other Elements – one common scenario is to bind two pieces of WPF UI to each-other. For example binding a slider to the “zoom” on a ScaleTransform. This is done by setting the ElementName property to the name of the element in the current name scope. Silverlight 2.0 beta 1 doesn’t support ElementName as a parameter when binding. This limitation can be worked around fairly easily by creating a simple object with a single property of the type you wish to glue together (double is probably the most common scenario) and then implementing INotifyPropertyChanged on that type. This approach is described in more detail here.
Data Templates – Both WPF and Silverlight 2.0 beta 1 share the concept of templates that can be applied to data. One area where SL 2 differs is that in WPF you can specify a template by the type of object the template applies to (by setting the DataType property). If this is set and no key is supplied (and the Datatemplate is appropriately scoped) the template becomes the default appearance for that type of data item in WPF. The DataTemplate type in Silverlight 2.0 beta 1 doesn’t include this property so all data templates are “keyed” in resource dictionaries or entered in-line. Data Triggers – Data templates in Silverlight 2.0 beta 1 don’t have data triggers like their WPF counterparts. This can be worked around using a converter, but requires more code than a data trigger would. Given the changes introduced by the new Silverlight control templating model data triggers going missing are the least of your worries.
TemplateBinding – TemplateBinding is fundamental to styling of controls, and thus has also made its way over from WPF to Silverlight.
ObservableCollection - the generic collection with built-in change notification, ObservableCollection has also been included in Silverlight 2.0 beta 1. The INotifyCollectionChanged interface (the collection equivalent of INotifyPropertyChanged) is also present, and implemented by ObservableCollection.

 

posted on 4/13/2008 10:32:38 PM


What is the equivalent of the ASP.NET Repeater in WPF?

The ASP.NET repeater is a great control for creating an arbitrary templated look for lists of data in ASP.NET web applications. WPF's databinding bears a great deal of similarity to the templating support found in the repeater, taking the power of templating even further by allowing templates to be defined as resources and re-used in multiple contexts, and in lots of different types of controls. However in spite of this there is no Repeater control in WPF.

Sample Repeater (from MSDN)
<asp:Repeater id="Repeater1" runat="server">
  <HeaderTemplate>
    <table border="1">
       <tr>
          <td><b>Company</b></td>
          <td><b>Symbol</b></td>
       </tr>
   </HeaderTemplate>
   <ItemTemplate>
     <tr>
       <td> <%# DataBinder.Eval(Container.DataItem, "Name") %> </td>
       <td> <%# DataBinder.Eval(Container.DataItem, "Ticker") %> </td>
     </tr>
   </ItemTemplate>
   <FooterTemplate>
     </table>
   </FooterTemplate>
</asp:Repeater>

How can you replicate the functionality  of the repeater in WPF? It turns out this is quite easy using an ItemsControl. ItemsControl is the base type that lots of list-like controls in WPF like ListBox, ComboBox and Menu which inherit from it either directly or indirectly. ItemsControl is also the parent to some list-like controls you might not expect such as the toolbar (which is really just a list of buttons and other controls, usually laid out horizontally) and StatusBar (once again, usually just a kind of horizontal list of controls). In spite of its fairly fundamental nature to lots of the usual suspects in the WPF controls namespace it isn't an abstract type and can be created in markup and bound like this:

ItemsControl Xaml Code
<ItemsControl ItemsSource="{Binding}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <!-- apply additional customizations for
      the items here in the template -->

      <TextBlock Text="{Binding}" />
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

The <DataTemplate> element allows us to specify how we want each item the ItemsControl is bound to, and the ItemsSource property on the ItemsControl populates the bound items from the data context (I'm assuming for the purposes of this demo that the stuff you want to bind to is in there). Another thing you may wish to do with the ItemsControl is to place it inside of a ScrollViewer control. The ASP.NET repeater generates HTML which is hosted in the browser, which handles showing a scroll-bar if the document is longer than can be displayed on a single screen. WPF Windows and Pages don't default to this way of operating, and thus you probably want to add the scroll viewer if more items are added to the ItemsControl than can be displayed inside the Window or Page.

Here is a complete page showing the list of binding modes available in WPF displayed in an ItemsControl. The ItemsControl has an ItemsPanel property that the bound items are layed out in. The default is a StackPanel, which is they type of panel you would want to reproduce the functionality of the ASP.NET Repeater. In this example below we've used the UniformGrid instead to control the layout of the items being bound. You can click here to run this page in your browser.

<Page
  xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation "
  xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml "
  xmlns:d="clr-namespace:System.Windows.Data;assembly=PresentationFramework"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  >
    <Page.Resources>
        <ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="bindingNames">
            <ObjectDataProvider.MethodParameters>
                <x:Type TypeName="d:BindingMode"/>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Page.Resources>
    <ItemsControl ItemsSource="{Binding}" DataContext="{StaticResource bindingNames}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!-- apply additional customizations for the items here in the template -->
                <TextBlock Text="{Binding}" FontSize="22"
                           Margin="5" Foreground="#feca00" />
        </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Page>

posted on 12/18/2007 12:56:25 AM


Read 'Lessons Learned' from the team at Vertigo that built the Family.Show WPF Sample

The team at Vertigo that created the nice Family.Show WPF sample wrote up a summary of their key feedback and take-aways from the project, and they're well worth a read. One tip in particular that I liked was regarding data binding, and default values. They advised setting the default values in bindings to give a better design-time experience in tools like Blend, which uses the defaults when it displays the UI in the designer. The source-code is also quite tractable, consisting of about a dozen xaml files and ~20 classes.

Family.Show screen shot  

posted on 4/30/2007 11:29:32 PM


How can I create an Image Reflection in WPF without having to hard-code the width and height?

Reflecting another visual in WPF is typically done using a VisualBrush and a ScaleTransform to “flip” the content upside down, as shown in this nice example on xamlog. In order to perform the “flip” the ScaleTransform needs the centre about which this should occur. Unfortunately the centre position of an element is not directly exposed via a property, so the net result of this is that for simple reflections (where you know the size of the source) you typically end up hard-coding the centre of the transform in your XAML . A recent poster in the WPF forums asked if it was possible to avoid this hard-coding. One approach which I’m going to explore here is to use data binding and a fairly generalized “arithmetic converter” capable of multiplying, dividing, adding to or subtracting from values as part of the binding operation . In order to obtain the center for our ScaleTransform we bind the CenterX property of the transform to the ActualWidth of the element we want to reflect, and multiply by 0.5. Similarly we can bind the CentreY property of the transform to the ActualHeight * 0.5. The arithmetic operation is specified to the converter using the ConverterParameter property of the binding. In order to use the converter we first need to add a namespace alias to the CLR namespace that the converter is contained in.

<Window x:Class="LearnWPF.ReflectionWithoutHardCodingWidth.Window1"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation "
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml "
    xmlns:cvrt="clr-namespace:LearnWPF.Converters"
    Title="LearnWPF.ReflectionWithoutHardCodingWidth" Height="300" Width="300"
    >
Then we can use the converter like so to perform the binding.

<ScaleTransform ScaleX="1" ScaleY="-1"
    CenterX="{Binding ElementName=PhotoBorder,
                      Path=ActualWidth,
                      Converter={StaticResource arithConverter},
                      ConverterParameter=*0.5}"

    CenterY="{Binding ElementName=PhotoBorder,
                      Path=ActualHeight,
                      Converter={StaticResource arithConverter},
                      ConverterParameter=*0.5}"
/>

This generalized arithmetic converter is clearly over-engineered for the task of finding the centre of an element, but it has other applications when using bindings to control layout in WPF.
I’ve created a complete project, using the sample from Xamlog as a starting point which you can download here. Below are screen-shots of the reflection in action with images of different sizes and aspect ratios.

posted on 9/26/2006 6:51:00 AM


How can I Create a Bound Animation in WPF?

In a previous post Steve asks "is it possible to bind an animation using xaml?". The example below shows how, binding the duration of an animation to a value in a text box. The animation, which is triggered when the button is clicked, changes the button's background color from orange to brown. The duration of the animation is bound to the value entered in the text box using the same {Binding} markup extension used throughout WPF. Although in this example the animation is bound to another element it could be bound to other sources like data from a relational database or a value in an Xml file. 

Xaml Code (WPF Beta 2/June CTP)
<Window x:Class="LearnWPF.BoundAnimation.Window1"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation "
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml "
    Title="LearnWPF.BoundAnimation" Height="200" Width="350"
    >
  <StackPanel Margin="2">
    <Button Width="200" Height="50" Name="animateMe"
            Content="Click The Button to See Animation">
      <Button.Background>
        <SolidColorBrush x:Name="buttonBrush" />
      </Button.Background>
      <Button.Triggers>
        <EventTrigger RoutedEvent="Button.Click">
          <EventTrigger.Actions>
            <BeginStoryboard>
              <Storyboard Storyboard.TargetName="buttonBrush"
                          Storyboard.TargetProperty="Color" >
                <ColorAnimation To="#58290A" From="#feca00"
                          Duration="{Binding ElementName=durationText, Path=Text}" />
              </Storyboard>
            </BeginStoryboard>
          </EventTrigger.Actions>
        </EventTrigger>
      </Button.Triggers>
    </Button>
    <StackPanel Orientation="Horizontal" Margin="2">
      <TextBlock VerticalAlignment="Center">Animation Time (hours:minutes:seconds)</TextBlock>
      <TextBox Name="durationText" Text="0:0:1" /> 
    </StackPanel>
  </StackPanel>
</Window>

Button Color Changing from Orange to Brown

posted on 7/6/2006 4:18:05 AM


How can I display time information more graphically in WPF?

In this code sample I've created a re-usable WPF data template for displaying time information using an analog clock. This demo combines some of the WPF features I've talked about before - DataTemplate and converters, and combines them together for easy display of time information. Here is an example of the DataTemplate in action, used inside the ItemTemplate of a ListBox. It is displaying a list of simple ChatEntry objects - the ChatEntry has one field which is a DateTime.

Chat transcript with times shown using analog clocks

To display the clock showing the time value inside the list's ItemTemplate required the following Xaml. The Content is bound to the DateTime field of the current ChatInfo. It is not apparent in the client code that any special kind of display will be used at all.

Xaml Fragment (WPF Beta 2)
<ContentControl Content="{Binding Path=DateTime}"
    Height="60" Grid.Column="0"
    Grid.Row="0" Grid.RowSpan="2"/>

   
With the abundance of high-quality clock implementations for XAML around it was hard to pick a starting point for the clock DataTemplate. Eventually I chose Nathan Dunlap's attractive chrome-less clock. After stripping it back, removing the animations which made it "go" and the second hand I added it inside a DataTemplate inside my App.Xaml file. This will allow my DataTemplate to be used throughout the application. I wanted my DataTemplate to be used any time a DateTime needs displaying. In order to do this I needed to set the DataType attribute to DateTime for my DataTemplate. The DateTime class that resides in the System namespace in the mscorlib assembly. So that I could specify the DateTime type as the DataType for my template I needed to import the System namespace as shown below:

Xaml Fragment (WPF Beta 2)
<Application x:Class="TimeConverter.App"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation "
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml "
    StartupUri="Window1.xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:l="clr-namespace:TimeConverter"
    >
    <Application.Resources>

      <l:TimeToClockHandAngleConverter x:Key="timeToAngleConverter" />
     
      <DataTemplate DataType="{x:Type sys:DateTime}">
      <!-- stripped back clock from Nathan Dunlap in here -->
      </DataTemplate>

       
 </Application.Resources> 
</Application>

As you can see above I also imported the TimeConverter namespace from the current assembly. This is because I needed to write a custom converter for my template, so I could bind the angle of the hands to the number of minutes or hours in the DateTime instance the template was binding against. I wrote a single converter for converting hours and minutes, and passed a parameter to the converter to specify if it should return the angle of the hour hand, or the angle of the minute hand for the supplied time. Inside the DataTemplate the converter was used like this:

Xaml Fragment (WPF Beta 2)
<Rectangle x:Name="HourHand" ... >
  <Rectangle.RenderTransform>
 <RotateTransform Angle="{Binding Converter={StaticResource timeToAngleConverter},
 ConverterParameter=HourHand}"
/>
  </Rectangle.RenderTransform>

Thanks and kudos to Nathan Dunlap for creating a nice and easily subverted clock. You can download a complete sample including the template here.

posted on 6/19/2006 1:20:25 AM


How can I create a data binding in code using WPF?

When creating UI elements in code it is often necessary to programmatically bind them to data. Fortunately this is relatively straightforward as the following code-snippet using the Binding object from the System.Windows.Data namespace shows:

C# Source (WPF Beta 2)
TextBox nameTextBox = new TextBox();
Binding nameTextBinding = new Binding("Name");
nameTextBinding.Source = person;
nameTextBox.SetBinding(TextBox.TextProperty, nameTextBinding);
// set style on text box, add text box to container etc

This sample assumes you have a type called Person, and an instance called person created elsewhere. Person has a public property called name. First we create our text box (called nameTextBox) and a Binding object, setting the path string for the binding in the constructor. Then we set the data source to the person instance. Alternatively the nameTextBox could get its data through its DataContext or the DataContext of one of its ancestors. If this was the case setting the Source property on the binding would not be necessary.

Next we call the SetBinding() method on the nameTextBox instance, specifying a DependencyProperty and the binding we just created. The example above binds the TextProperty DependencyProperty of nameTextBox to the Name property of the person. In this case the DependencyProperty is a member of the TextBox itself, but it doesn't have to be. For example we can also bind attached properties that might pertain to the container the nameTextBox is placed in.

This example below binds (rather pointlessly) the TopProperty DependencyProperty of the Canvas to the current number of minutes that have elapsed in the current hour for a newly created textbox instance. If the textbox is then added to a canvas (the example assumes a canvas called mainCanvas) the binding will take effect, controlling the top of the textbox in the canvas.

C# Source (WPF Beta 2)
TextBox positionedTextBox = new TextBox();
Binding positionBinding = new Binding("Minute");
positionBinding.Source = System.DateTime.Now;
positionedTextBox.SetBinding(Canvas.TopProperty, positionBinding);
mainCanvas.Children.Add(positionedTextBox);

posted on 6/13/2006 8:21:12 PM


How do I format Numbers and Dates when using WPF Data Binding?

It is often desirable to control the format of dates, times, money and percentages when they are displayed. The example screen-shot below shows a list of 3 sale records. The sale information includes an Id, the sale amount, the percentage of sales tax paid and the time of the sale. Although the information displayed to the user is correct, the unformatted data might be difficult or confusing for a user to read.

unformatted dates, currency values and percentages

The .NET framework includes a small formatting mini-language using strings like "{0:C}" to format a parameter as currency. WPF data binding does not have any facility built-in to allow this formatting, however it is easy to add by extending the built-in binding infrastructure. This technique I originally came across here in the WPF forums, but it has been extended here to allow formatting of all data types.

Implementing a custom ValueConverter for Formatting
To extend the binding infrastructure to allow formatting I've created a ValueConverter to convert between a .NET object and a string. Value converters implement the IValueConverter interface in the System.Windows.Data namespace. This interface has two methods, Convert and ConvertBack for converting between two types. To convert the data from a .NET object to a formatted string we're only going to implement the Convert() method. The formatting string (like "{0:MM-dd-yyyy}" if we wished to format a date) is passed to the Convert() method of the ValueConverter via the aptly named parameter parameter. Fortunately the Convert() method is also passed a CultureInfo parameter which we can use to perform our formatting in a culture-specific way. Formatting should be culture aware, as different countries use different symbols for currency, have different date time formats and different symbols to separate the whole and fractional parts of non-integer real numbers.  The code for the ValueConverter is shown below:

C# Code (Feb 2006 CTP)

using System;
using System.Windows.Data;

namespace LearnWPF.FormattingAndDataBinding
{
    [ValueConversion(typeof(object),typeof(string))]
    public class FormattingConverter: IValueConverter
    {
        public object Convert(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            string formatString = parameter as string;
            if (formatString != null)
            {
                return string.Format(culture, formatString, value);
            }
            else
            {
                return value.ToString();
            }
        }

        public object ConvertBack(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
        {
            // we don't intend this to ever be called
            return null;
        }
    }
}

Using the Converter from our WPF Application
To use the converter in our WPF application requires 3 steps:

1 - Create an Xml namespace prefix for the CLR namespace that contains the ValueConverter. This is necessary any time you want to use one of your own types in mark-up. The example below tells the Xaml run-time that any time it sees a "my" prefix on an element it should look in the LearnWPF.FormattingAndDataBinding namespace in the current assembly. More details of this can be found here in the Windows SDK.

xmlns:my="clr-namespace:LearnWPF.FormattingAndDataBinding"

2 - Create an instance of our formatter as a resource*. In this sample I've chosen to place it in the resources dictionary for the window. A key is required so we can retrieve it later.

<my:FormattingConverter x:Key="formatter" />

3 - Use the Converter when binding. We do this by specifying a Converter for the binding (the converter we created in step 2 as a resource), and also setting the ConverterParameter. The ConverterParameter is passed to the IValuConverter's Convert() method as the (aptly named) parameter parameter. The example below passes a custom date format string {0:dd-MMM-yyy hh:mm}.

<TextBlock Text="{Binding Path=TimeOfSale,
  Converter={StaticResource formatter},
  ConverterParameter=' \{0:dd-MMM-yyyy hh:mm\}'
}" />

 
Note that in the format string the curly brackets are escaped using the backslash character like this \{ and this \}. This is necessary because the curly brackets are used in Xaml for specifying markup extensions like that {Binding} and {StaticResource} extensions seen in this example. We need to differentiate our formatting string from those. 
   
Here is the Xaml code containing all three steps

Xaml Code (Feb 2006 CTP)

<Window x:Class="LearnWPF.FormattingAndDataBinding.Window1"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation "
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml "
    xmlns:my="clr-namespace:LearnWPF.FormattingAndDataBinding"
    Title="LearnWPF.FormattingAndDataBinding" Height="300" Width="300"
    Loaded="windowLoaded"
    >
  <Window.Resources>
    <ObjectDataProvider x:Key="sales" />
    <my:FormattingConverter x:Key="formatter" />
  </Window.Resources>
  <ListBox DataContext="{StaticResource sales}" ItemsSource="{Binding}">
    <ListBox.ItemTemplate>
      <DataTemplate>
        <Border BorderBrush="#feca00" BorderThickness="2"
                CornerRadius="3" Padding="5" Margin="2">
          <StackPanel Orientation="Horizontal">

            <!-- formatting the Id -->
            <TextBlock Text="{Binding Path=Id,
              Converter={StaticResource formatter},
              ConverterParameter='Sale No:\{0\} '}" />

            <!-- formatting the Amount -->
            <TextBlock Text="{Binding Path=Amount,
              Converter={StaticResource formatter},
              ConverterParameter=' \{0:C\}'}"
              FontWeight="Bold" />

            <!-- formatting the SalesTaxPercentage -->
            <TextBlock Text="{Binding Path=SalesTaxPercentage,
              Converter={StaticResource formatter},
              ConverterParameter=' (\{0:P\} Sales Tax)'}" />

            <!-- formatting the date -->
            <TextBlock Text="{Binding Path=TimeOfSale,
              Converter={StaticResource formatter},
              ConverterParameter=' \{0:dd-MMM-yyyy hh:mm\}'}" />

          </StackPanel>
        </Border> 
      </DataTemplate>
    </ListBox.ItemTemplate>
  </ListBox>
</Window>

Here is the resulting window with nicely formatted data

Formatted dates, currency values and percentages

The formatting converter shown above only performs a one-way conversion - from the .NET object to a string. Converting back to the underlying data type from a string might be possible by inspecting the targetType passed as an argument to the ConvertBack() method, or you could write a type-specific converter with a tailored ConvertBack() implementation. Since the formatting converter only converts in one direction it is really only useful for formatting data for display in a read-only manner.

You can download the complete source code for this example here.

* Note: It is not absolutely necessary to create our Converter as a resource, since we could use the less-compact property element syntax for the binding and create an instance of the Converter each time we wanted to use it. Defining the converter as a resource and re-using it is recommended.

posted on 5/13/2006 10:43:25 PM


How do I prevent BamlParseExceptions when binding some object properties?

WPF's data binding facilities are extremely powerful - sometimes when using this power you may experience BamlParseException with an error message stating that the was a problem converting from a Binding object to some other type. A typical error message might look like this:

Error at element 'RuntimePropertyInfo' in markup file 'Window1.xaml' : Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'

This problem can be confusing at first because Elements with the same DataContext in your Xaml file may be able to bind to the same piece of data without any problems.

<Window.Resources>
  <XmlDataProvider x:Key="data" XPath="//item">
    <x:XData>
      <items xmlns="">
        <item val="foo"/><item val="bar" />
      </items>
    </x:XData>
  </XmlDataProvider>
</Window.Resources>
<StackPanel>
  <!-- this works -->
   <TextBlock Text="{Binding
XPath=@val }" />
  <!-- this does not -->
  <TextBlock>
    <Bold Text="{Binding
XPath=@val}"/ >
  </TextBlock>

</StackPanel>

If this is the case it can be indicative of a subtle problem not with the source of the data but with the property you're trying to bind the data to. WPF data binding makes use of the dependency property system built into WPF, and the eventual target of the {Binding} markup extension must be a dependency property. Dependency properties are not the same as CLR properties, which are a syntactic convenience which allows a pair of get and set methods for a member to be treated from a code perspective like a member field. Dependency properties on the other hand are objects of type DependencyProperty. Most of the UI-related properties of controls in WPF eventually call dependency properties internally, so it is easy to forget this rule.

It is not easy to know at a glance if a CLR property does indeed call a dependency property or not. The current WPF documentation does not explicity indicate this. The documentation does list the public fields of an object, which typically includes all the dependency properties as static fields. If the property you're trying to bind to does not have a static DependencyProperty member variable with the name of the CLR property, followed by 'Property' (e.g. TextProperty) then the CLR property is unlikely to be using the dependency property system underneath, and thus is not a suitable target for binding. Using Reflector to look inside the property getter and setter methods it is easy to spot the difference between the two.

CLR Property which calls a DependencyProperty (TextBlock.Text)

public string Text
{
      get
      {
            return (string) base.GetValue(TextBlock.TextProperty);
      }
      set
      {
            base.SetValue(TextBlock.TextProperty, value);
      }
}

CLR Property which does not call a DependencyProperty (Bold.Text), which we cannot bind to.

public string Text
{
      get
      {
            return TextRangeBase.GetTextInternal(base.ContentStart, base.ContentEnd);
      }
      set
      {
            if (value == null)
            {
                  value = string.Empty;
            }
            TextContainer container1 = base.TextContainer;
            container1.BeginChange();
            try
            {
                  TextPointer pointer1 = base.ContentStart;
                  if (!base.IsEmpty)
                  {
                        container1.DeleteContentInternal(pointer1, base.ContentEnd);
                  }
                  Run run1 = Inline.CreateImplicitRun(this);
                  pointer1.InsertTextElement(run1);
                  run1.Text = value;
            }
            finally
            {
                  container1.EndChange();
            }
      }
}


In some cases it is possible to work around this problem - if you are using data binding to keep two things synchronized and the other thing is a dependency property then swapping the source and target of the binding can solve this problem.

posted on 4/21/2006 6:43:04 AM


How can I display my business objects in a consistent way across different forms in WPF?

Defining something in a single place for re-use in multiple places is a common goal for developers. In UI frameworks like ASP.NET or windows forms re-using pieces of UI is typically done by creating user controls or custom controls. Unfortunately the places where you can easily use these is often limited. For example if you create a UserControl in ASP.NET to display an employee there is no easy way to re-use that control when displaying a list of customers in a combo box. WPF allows the display of business objects and other data to be templated like controls, and because of WPF's rich content model these data templates can be used in many different places.

Lets look at the steps we would go through to create a simple data template for displaying employee data. First lets assume that our employee type has the following public properties, all of which are strings:

  • Department
  • EmailAddress
  • ImagePath
  • JobDescription 
  • Name
  • Title

We might wish to lay out our employee data as shown below: an image of the employee on the left followed by with the employee name, email address and other details layed out as shown.

desired layout for employee display

In order to create the DataTemplate we'll first examine the regular Xaml to display the layout shown above statically (without any data binding) and then add a little data binding code to turn this into a DataTemplate we can use anywhere we want to show employees. The Xaml markup below creates the static layout we want, with appropriate text placeholders for the fields we'll eventually be exposing from the Employee object. To achieve this layout we used a Grid panel, one of the most flexible layout panels in WPF. We created a 3x3 grid of rows and columns by adding the appropriate <ColumnDefinition/> and <RowDefinition/> elements to the Grid. Then we add the actual placehoders to the Grid - TextBlock elements and a single Image element. We control the placement of these elements in the Grid by setting the Grid.Row and Grid.Column attributes. This notation in the form of ParentElement.PropertyName is called Property-Element syntax. This Xaml is actually setting properties on the parent Grid element, placing child elements in the appropriate rows and columns.

<Grid ShowGridLines="True" Background="Transparent">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="55" />
    <ColumnDefinition />
    <ColumnDefinition />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition />
    <RowDefinition />
    <RowDefinition />
  </Grid.RowDefinitions>
  <Image Width="50" Stretch="Uniform"
         Source="pack://application:,,/Media/head-male-sillouette.gif"
         Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"/>
  <TextBlock FontSize="20" Grid.Column="1" Grid.Row="0"
             Foreground="Orange" TextDecorations="Underline"
             Text="Data Bound: Name"/>
  <TextBlock FontSize="12" Grid.Column="1" Grid.Row="1"
             Foreground="Blue" TextDecorations="Underline"
             Text="Data Bound: EmailAddress" />
  <TextBlock FontSize="16" Margin="10,0,10,0" Grid.Column="2"
             Grid.Row="0" Foreground="Black"
             Text="Data Bound: Title" />
  <TextBlock FontSize="16" Margin="10,0,10,0" Grid.Column="2"
             Grid.Row="1" Foreground="Black"
             Text="Data Bound: Department" />
  <TextBlock FontSize="12" Grid.Column="0" Grid.ColumnSpan="3" 
             Grid.Row="2" Foreground="Black"
             Text="Data Bound: JobDescription (this one can span multiple columns)"
             TextWrapping="Wrap" />
</Grid>

To Convert this Xaml into a DataTemplate, all that is required is to change the currently static TextBlock text to something bound to the employee object. This is done with the Binding markup extension {Binding Path=PropertyName}, using the name of the property you wish to mind to in the Path portion of the binding statement. The image source is also just a string, so we can bind the source of the image to that to. We also need to place our Xaml in a DataTemplate element and assign it a DataType. By placing the DataTemplate in the Application resource dictionary in MyApp.xaml we can use this template anywhere in our application we are binding to employee data. The finished data template is shown below. The text in orange shows the changes necessary to convert from static Xaml to the DataTemplate.

<DataTemplate DataType="{x:Type l:Employee}">
  <Grid Background="Transparent">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="55" />
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>
    <Image Width="50" Stretch="Uniform"
           Source="{Binding Path=ImagePath}"
           Grid.Column="0" Grid.Row="0" Grid.RowSpan="2"/>
    <TextBlock FontSize="20" Grid.Column="1" Grid.Row="0"
           Foreground="Orange" TextDecorations="Underline"
           Text="{Binding Path=Name}"/>
    <TextBlock FontSize="12" Grid.Column="1" Grid.Row="1"
           Foreground="Blue" TextDecorations="Underline"
           Text="{Binding Path=EmailAddress}" />
    <TextBlock FontSize="16" Margin="10,0,10,0" Grid.Column="2"
           Grid.Row="0" Foreground="Black" Text="{Binding Path=Title}"/>
    <TextBlock FontSize="16" Margin="10,0,10,0" Grid.Column="2"
           Grid.Row="1" Foreground="Black" Text="{Binding Path=Department}"/>
    <TextBlock FontSize="12" Grid.Column="0" Grid.ColumnSpan="3" 
           Grid.Row="2" Foreground="Black" Text="{Binding Path=JobDescription}"
           TextWrapping="Wrap" />
  </Grid>
</DataTemplate>

We don't need to do anything special in our application to use the DataTemplate. Any time an element is bound to an employee, or list of employees the DataTemplate will be used. For this example we added an ObjectDataProvider to the Application resource dictionary (in MyApp.xaml) which returns a collection containing 4 employee objects. We then set it as the DataContext for all the items in our main window. Below is the Xaml for binding the contents of a button to a single employee, and for binding a ComboBox to the list of employees. You can download the full source for this sample here.

<StackPanel Margin="10" DataContext="{StaticResource Employees}">
    ...
    <Button Content="{Binding Path=[0]}" />
    <ComboBox ItemsSource="{Binding}" SelectedIndex="0" />
 </StackPanel>

Button and combo box 

posted on 3/31/2006 6:32:19 AM


How do I bind to XML data in WPF?

WPF has good built-in support for binding to different kinds of data, including XML. In this very simple example we're going to declare a small "island" of XML data in our UI, and bind some text properties to parts of the XML document. Then we'll look at binding to XML documents loaded from other sources. 

We declare the XML data island by adding an XmlDataProvider to the resources collection of our window. Assigning a key to the resource is necessary so we can access it later, and setting an XPath expression specifies the list of nodes the XmlDataProvider will expose. The built-in support for using XPath when binding to XML data is a powerful feature of XML data binding in WPF, and should feel fairly natural for those familiar with XSLT. In this case the expression says to return all the Employee nodes located under a root Employees node. Inside the XmlDataProvider we add an XData node (this is a requirement for XML data islands). Inside the XData node we place any XML content we wish. For this example we've defined a simple set of XML data - a list of employees with one item in the list, Microsoft CEO Steve Ballmer.

<Window.Resources>
    <XmlDataProvider x:Key="EmployeeData" XPath="/Employees/Employee">
      <x:XData>
        <!-- xml data island -->
        <Employees xmlns="">
          <Employee Name="Steven Ballmer" DOB="1-Mar-1956">
            <Title>CEO</Title>
          </Employee>
        </Employees>

      </x:XData>
    </XmlDataProvider>
</Window.Resources>

To bind to this XML in our application code we use a binding syntax similar to the one used to bind to objects. First we set the DataContext for the panel so that all the child Xaml elements are binding to the same data. This is done using the {StaticResource} markup extension with a key, the key we previously gave our XmlDataProvider. Inside the panel there are two text blocks that will be bound to parts of the Employees XML document. Once again the syntax for binding is similat to the syntax used to bind to objects. We use the {Binding} markup extension, but instead of setting a Path, we specify an XPath expression. To bind to the Name attribute on an employee element the expression is @Name, but more complex espressions are possible such as the second example which binds to the inner text of the title element nested under the employee element.

<!-- binding to data island -->
<StackPanel DataContext="{StaticResource EmployeeData}">
    <TextBlock Text="{Binding XPath=@Name}" FontSize="30" />
    <TextBlock Text="{Binding XPath=Title/text()}" FontSize="30" />
</StackPanel>

In the real world it is more likely that XML data will be retrieved from an external source rather than imbedded in the UI. This is also easy to achieve using the XmlDataProvider and setting the Source. This example shows how to retrieve the RSS feed from LearnWPF, but XML can also be loaded from the file system or imbedded XML documents.

<XmlDataProvider x:Key="LearnWPFFeed"
                     Source="
http://learnwpf.com/Rss.ashx "  
                     XPath="//item" />

                    
Binding to nodes retrieved from an external source is the same as when we bound to local XML data.

<!-- binding to RSS feed -->
<StackPanel DataContext="{StaticResource LearnWPFFeed}">
  <TextBlock Text="{Binding XPath=title/text()}" FontSize="30" />
  <TextBlock Text="{Binding XPath=link/text()}" FontSize="12" />
</StackPanel>

Simple UI showing bound data from XML sources

The full source for this window with both the data sources is here.

posted on 3/21/2006 3:01:10 PM


I want to bind control values to object properties in WPF – how can I do that?

WPFs data binding capabilities prevent developers having to write the brittle, hard-to-maintain code otherwise required to keep changes in the UI synchronized with changes in their own objects. It also handles conversion between an object’s data types and types that can be displayed in our UI. This example will show the most basic kind of data binding – binding text values for simple UI elements to properties of a .NET object. Further examples will cover binding to lists of objects, binding to non-text properties and the like. This example will lay the conceptual foundations for further understanding WPF data binding.

The object we will be binding to is an Employee object and is extremely simple – it has two read/write properties (Name and Department) and a third read-only Id property (a GUID). The UI to display this employee in is equally simple. We have two text boxes to allow the Name and Department properties to be edited, and a third Label control for displaying the ID. All these display fields are labeled accordingly.

Simple UI for editing Employees 

In order for us to perform the binding we’re going to need the following things

  1. an Employee instance for the UI to bind to (the data)
  2. Some way of telling our UI elements to bind to that employee instance
  3. Notation for specifying to the UI elements which properties of the employee to display

Creating a new employee instance (#1) is simple – it is just a plain old .NET object, which can be created in any number of ways. The way we point our UI markup (XAML) code to that object instance (#2) is by adding an ObjectDataProvider to our Window’s list of resources. When we define it we give it a key so we can refer to it later. This will be the point of indirection that we will use to plug our Employee object created at run-time into our UI.

<Window.Resources>
<ObjectDataProvider x:Key="employeeData"/>

Once we’ve defined the ObjectDataProvider we still haven’t quite covered off point #2 yet. We’ve created a place where the Employee object can be “provided”, but we still need to tell our text boxes and labels to use that data provider. Now we could go through and connect each control to the data provider but as our Employee object gets more complicated, or we start to want to show data from different objects on a single form this approach breaks down as we have to maintain the same value in many places. It would be desirable if controls that are grouped together on the screen could somehow share a kind of data context, so that each of them pointed to the same underlying data automatically. Fortunately in WPF there is – it is called the DataContext, and it works with the hierarchical nature of WPF element. Child elements automatically inherit the DataContext of their parent element.
In the sample application all the elements we want to display data in are children of the Grid used for controlling the layout, so we will specify the DataContext for the Grid like so:

<Grid DataContext="{StaticResource employeeData}">

The {StaticResource} MarkupExtension looks up the resource we created in the Window.Resources section. It find it using the key we supply, and assigns that to the data context for the grid and its child elements.

The next step is to specify to the UI elements which properties they should display. We do this using another MarkupExtension, the {Binding} markup extension which allows us to specify which properties we want to display using the following syntax:

<TextBox Text="{Binding Path=Name}"/>

Bindings between the UI fields and the Employee object

This is all that we need to do in the XAML markup to bind the Employee to the various fields on the form. The last thing we need to do is to create an Employee instance in our application code, and associate it with the ObjectDataProvider. This is done in the example using the following VB.NET code (_ceo is an Employee instance we have created):

Dim employeeProvider As ObjectDataProvider = _
CType(FindResource("employeeData"), ObjectDataProvider)
employeeProvider.ObjectInstance = _ceo

In order to verify that changes to the UI were also reflected in the underlying Employee object we’ve also added a button. When clicked the button displays a message box showing the output of the ToString method of the Employee. We overrode the base ToString method to write out the Name, Department and Id for the Employee object.

Hopefully this has shown you how simple WPF data-binding can be. When combined with other features of the platform such as templating it provides a great way to visualize and manipulate your data. Stay tuned for more involved data binding topics.

posted on 3/1/2006 1:42:34 AM


How do I allow the user to resize a region of a form in WPF using just XAML?

In a previous how-to we looked at how to use a ScaleTransform to allow the user to re-size a region of a form using a slider control. When the value of the slider changed some C# code in the event handler created a new ScaleTransform, set its ScaleX and ScaleY values based on the value of the slider, and then assigned the ScaleTransform to the LayoutTransform of the item we wanted to re-size. It is also possible to do this without writing any "code" by creating a ScaleTransform in XAML and binding the ScaleX and ScaleY properites of the transform to the value of the slider.

WPF has some powerful data binding capabilities - usually people think of data binding as binding the property of a control to some underling data-structure - either relational data, XML or some "business object" from the problem domain. Binding can also be used to bind the value of two UIElements together. In the sample code (shown in full below) we've defined a slider in the same way as the previous example, but without specifying a ValueChanged handler.

<Slider Name="UISizer" Minimum="0.1" Maximum="5" Value="1">

Then for the grid we wish to re-size we add a child LayoutTransform element, and inside that we nest our ScaleTransform. The values for the ScaleX and ScaleY properties are bound to the value of the slider using the Binding markup extension. Markup extensions are defined inside the curly braces, and look similar to the way XPath functions can be used in XSLT. This binding expression tells WPF that the ScaleX and ScaleY properties should be bound to the Value property of the UISizer element. 

<Grid Name="ItemToResize" Background="#feca00" Width="500">
    <Grid.LayoutTransform>
        <ScaleTransform ScaleX="{Binding ElementName=UISizer, Path=Value}"
          ScaleY="{Binding ElementName=UISizer, Path=Value}" />
    </Grid.LayoutTransform>

The complete XAML (below) does all that the previous demo did, without requiring any C# or VB.NET code.

XAML (For Feb CTP):

<Window x:Class="ScaleTest.Window1"
    xmlns="
http://schemas.microsoft.com/winfx/2006/xaml/presentation "
    xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml "
    Title="ScaleTest" Height="300" Width="300"
    >
  <StackPanel Orientation="Vertical">
    <StackPanel Orientation="Horizontal">
      <TextBlock FontSize="12">Smaller</TextBlock>
      <Slider Name="UISizer" Minimum="0.1" Maximum="5" Value="1">
      </Slider>
      <TextBlock FontSize="20">Bigger</TextBlock>
    </StackPanel>
    <Border BorderThickness="3" BorderBrush="#58290A">
      <Grid Name="ItemToResize" Background="#feca00" Width="500">
        <Grid.LayoutTransform>
          <ScaleTransform ScaleX="{Binding ElementName=UISizer, Path=Value}"
          ScaleY="{Binding ElementName=UISizer, Path=Value}" />
        </Grid.LayoutTransform>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="Auto" />
          <ColumnDefinition  Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition />
          <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Grid.Column="0" Grid.Row="0" FontSize="15">Foo:</TextBlock>
        <TextBlock Grid.Column="0" Grid.Row="1" FontSize="15">Bar:</TextBlock>
        <TextBox Grid.Column="1" Grid.Row="1" Padding="3"></TextBox>
        <ComboBox Grid.Column="1" Grid.Row="0" Padding="3">
          <ListBoxItem>
            <TextBlock>Value 1</TextBlock>
          </ListBoxItem>
          <ListBoxItem>
            <TextBlock>Value 2</TextBlock>
          </ListBoxItem>
          <ListBoxItem>
            <Ellipse Width="50" Height="35" Fill="Orange" />
          </ListBoxItem>
          <ListBoxItem>
            <TextBlock>Value 4</TextBlock>
          </ListBoxItem>
        </ComboBox>
      </Grid>
    </Border>
    <TextBlock FontSize="20">This item will not change its size...</TextBlock>
  </StackPanel>
</Window>

posted on 2/24/2006 5:01:13 PM