Archive for the 'WPF' Category

Animations in WPF

Animations in WPF

Animations in WPF are not like the cartoons that you see on TV or in the movies. In WPF an animation is a mechanism that changes the value of a dependency property over time. Animations can be used to add dramatic and appealing effects to a user interface provided that one resists the ever present temptation to overuse them. Animation is a deep topic, implemented in WPF with well over 150 classes. This post will only scratch the surface.

The example here expands on the example in my last post. In this XAML only example RenderTransforms are animated to produce quirky mouse over effects. This is what is displayed before the mouse cursor is moved over any of the images.

anim_tools

The Style for the bell image applies a RotateTransform with its origin approximately at the bell’s handle. By default it rotates the image zero degrees, so nothing is changed. However event triggers launch a Storyboard that animates the RotateTransform making the bell look like it is being rung.

<Storyboard x:Key="ringStoryboard">
  <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"
    To="10" Duration="0:0:0.2"/>
  <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"
    To="0" BeginTime="0:0:0.2" Duration="0:0:0.2"/>
</Storyboard>
<Style x:Key="bellImage" TargetType ="{x:Type Image}">
  <Setter Property="RenderTransformOrigin" Value="0.6,0.2"/>
  <Setter Property="RenderTransform">
    <Setter.Value>
        <RotateTransform/>
    </Setter.Value>
  </Setter> 
  <Style.Triggers>
    <EventTrigger RoutedEvent="Image.MouseEnter">
        <EventTrigger.Actions>
            <BeginStoryboard Storyboard="{StaticResource ringStoryboard}" />
        </EventTrigger.Actions>
    </EventTrigger>
    <EventTrigger RoutedEvent="Image.MouseLeave">
        <EventTrigger.Actions>
            <BeginStoryboard Storyboard="{StaticResource ringStoryboard}" />
        </EventTrigger.Actions>
    </EventTrigger>
  </Style.Triggers>
</Style>

A few things need to be explained at this point. Storyboard is simply a class that wraps one or more animations. More importantly a Storyboard can be wrapped by a BeginStoryboard. BeginStoryboard inherits from TriggerAction, so it can be set as the action of any event or property trigger. The animation classes are not TriggerActions, so they cannot be directly set as a trigger’s action.

The animations in this Storyboard are altering the Angle property of the RotateTransform. Angle is type Double, so the class DoubleAnimation must be used to animate it. There are other animation classes for use with other data types, e.g. Int32Animation. Consult MSDN.

The first DoubleAnimation changes Angle to a value of 10 (To=”10″) over a period of 0.2 seconds (Duration=”0:0:0.2″). It changes it to 10 from whatever its present value is. Angle’s default value is 0, so that is its starting point. The second animation begins at 0.2 seconds (BeginTime=”0:0:0.2″), i.e. after the first has completed. It animates Angle back to 0 over a period of 0.2 seconds. You must download the example code and try this yourself to see the result. Just open anim.xaml in your favorite XAML editor. The zip file contains the needed images but the paths will likely be different on your machine. Just change the image paths and run the XAML.

For the tools image a ScaleTransform is animated to make the image appear to grow when the mouse cursor is moved over it. It shrinks back to normal size when the mouse cursor is moved away. Here a PropertyTrigger is used instead of EventTriggers just to demonstrate its use. EventTriggers could have been used here to achieve the same effect. Likewise a PropertyTrigger could have been used on the bell.

<Style x:Key="toolsImage" TargetType ="{x:Type Image}">
  <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
  <Setter Property="RenderTransform">
    <Setter.Value>
        <ScaleTransform/>
    </Setter.Value>
  </Setter> 
  <Style.Triggers>
    <Trigger Property="IsMouseOver" Value="True">
        <Trigger.EnterActions>
            <BeginStoryboard Storyboard="{StaticResource expandStoryboard}" />
        </Trigger.EnterActions>
        <Trigger.ExitActions>
            <BeginStoryboard Storyboard="{StaticResource shrinkStoryboard}" />
        </Trigger.ExitActions>
    </Trigger>
  </Style.Triggers>
</Style>

The pencil image also uses a ScaleTransform except that the RenderTransformOrigin is set to approximately where the pencil tip is. This makes the pencil seem to grow lengthwise instead of uniformly in two dimensions as the tools did. The thumb image uses a SkewTransform to make it appear that a “thumbs-up” is being given. The animation for the hourglass is more complex, so I’ll explain it in a future post. In the mean time you can see what it does by running the XAML example.

The images used in this example were provided by the kind folks at VistaICO.com. Source code for this example may be downloaded here.

Advertisements

LayoutTransform vs. RenderTransform in WPF

Every FrameworkElement in WPF, in other words every visual element that we deal with in WPF, has two properties to support display transformations, LayoutTransform and RenderTransform. RenderTransform is actually inherited from FrameworkElement’s base class, UIElement. Both LayoutTransform and RenderTransform are of type Transform.

Transform is an abstract class, and WPF provides several concrete implementations that can be applied to the two aforementioned properties in XAML and code. Some of them are:

  • RotateTransform
  • ScaleTransform
  • SkewTransform
  • TranslateTransform

So, what is the difference between LayoutTransform and RenderTransform? The two property names reveal much in this case. Any Transform assigned to LayoutTransform is applied when layout is performed. RenderTransform is applied after layout when rendering is performed. A quick XAML example will demonstrate this. Copy/paste the XAML below into XAMLPad, Kaxaml, or your favorite XAML editor. You’ll have to supply your own images or download them from the link at the bottom of this post as I haven’t uploaded them yet. Just change the path where you see <Image Source="c:/code/mywpf/anim/.../>.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Page.Resources>
    <!-- Style for border around each image -->
    <Style x:Key="imageBorder" TargetType="{x:Type Border}">
      <Setter Property="Width" Value="100"/>
      <Setter Property="Height" Value="130"/>
      <Setter Property="Margin" Value="4,0,0,0"/>
      <Setter Property="BorderThickness" Value="3"/>
      <Setter Property="BorderBrush" Value="Khaki"/>
      <Setter Property="Background" Value="Beige"/>
      <Setter Property="CornerRadius" Value="6"/>
      <Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
    </Style>
  </Page.Resources>

  <StackPanel>
    <Label>LayoutTransform:</Label>
    <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Background="#aaa" Height="140">
      <Border Style="{StaticResource imageBorder}">
        <Border.LayoutTransform>
          <RotateTransform Angle="10"/>
        </Border.LayoutTransform>
        <Image Source="c:/code/mywpf/anim/alert.png">
        </Image>
      </Border>
    
      <Border Style="{StaticResource imageBorder}">
        <Border.LayoutTransform>
          <RotateTransform Angle="-12"/>
        </Border.LayoutTransform>
        <Image Source="c:/code/mywpf/anim/config-tools.png">
        </Image>
      </Border>
    </StackPanel>

    <Label>RenderTransform:</Label>
    <StackPanel Orientation="Horizontal" VerticalAlignment="Top" Background="#aaa" Height="140">
      <Border Style="{StaticResource imageBorder}">
        <Border.RenderTransform>
          <RotateTransform Angle="10"/>
        </Border.RenderTransform>
        <Image Source="c:/code/mywpf/anim/alert.png">
        </Image>
      </Border>
    
      <Border Style="{StaticResource imageBorder}">
        <Border.RenderTransform>
          <RotateTransform Angle="-12"/>
        </Border.RenderTransform>
        <Image Source="c:/code/mywpf/anim/config-tools.png">
        </Image>
      </Border>
    </StackPanel>
  </StackPanel>
</Page>

The result should look like this.
transforms
A pair of Borders is created, each containing a single image. A RotateTransform is assigned to the LayoutTransform property of each border. This causes each Border and its contents to be rotated slightly, the first by positive 10 degrees and the second by negative 12 degrees. Margins, as defined in the imageBorder Style, between the Borders is maintained since the transform is applied at layout time. The Borders are fully contained within the containing StackPanel, being clipped to within the panel’s dimensions.

The Borders are repeated on the second row. This time RenderTransfom is used instead of LayoutTransform. Notice that the two Borders now overlap and are not clipped to the containing StackPanel. In this case the Borders were positioned and clipped in an untransformed state, i.e. unrotated. Then the RotateTransform was applied to each Border with the results shown here.

The images used in this example were provided by the kind folks at VistaICO.com

Consuming RESTful Web Services in WPF

It turns out that consuming the RESTful web service created in my last post is very simple when WPF’s XML data binding features are used. I have previously posted about binding to XML data in a WPF application.

My RESTful web service uses XML namespaces in its return data, so I first declare an XmlNamespaceMappingCollection in my WPF application XAML. Next I declare an XmlDataProvider for the composer list and set its Source property to the URI of my Composers RESTful operation. A second XmlDataProvider is declared for the composition data, but that is still empty at this time.

<Window.Resources>
    <XmlNamespaceMappingCollection x:Key="NamespaceMapping">
        <XmlNamespaceMapping Uri="https://patconroy.wordpress.com/data" Prefix="pc" />
    </XmlNamespaceMappingCollection>
    <XmlDataProvider x:Key="ComposerData" 
                     XmlNamespaceManager="{StaticResource NamespaceMapping}"
                     Source="http://localhost:8000/service/restbaroque/composers"/>
    <XmlDataProvider x:Key="CompositionData"
                     XmlNamespaceManager="{StaticResource NamespaceMapping}"/>
</Window.Resources>

A ListBox created on the main Window that binds to the ComposerData XML source. Note that the StringFormat property used on the MultiBinding here was introduced in the 3.5 SP1 version of the framework. It is not available in earlier versions.

<ListBox x:Name="_composerList" Margin="40,20" 
                 ItemsSource="{Binding Source={StaticResource ComposerData}, XPath=//pc:Composers/pc:Composer}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <TextBlock>
                <TextBlock.Text>
                    <MultiBinding StringFormat="{}{0} {1} {2}">
                        <Binding XPath="pc:FirstName"/>
                        <Binding XPath="pc:MiddleName"/>
                        <Binding XPath="pc:LastName"/>
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

That’s all the work the needs to be done to display the composer list. A Click event handler for a button on the Window sets the appropriate Source for the compositions XmlDataSource.

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (_composerList.SelectedItem == null)
    {
        MessageBox.Show("Please select a composer");
    }
    else
    {
        XmlNamespaceManager ns = Resources["NamespaceMapping"] as XmlNamespaceManager;
        XmlNode node = _composerList.SelectedItem as XmlNode;
        string id = node.SelectSingleNode("pc:Id", ns).InnerText;
        string uriString = String.Format("http://localhost:8000/service/restbaroque/composers/{0}/compositions", id);
        Uri uri = new Uri(uriString);
        XmlDataProvider dp = Resources["CompositionData"] as XmlDataProvider;
        dp.Source = uri;
    }
}
 

A second ListBox on the Window binds to the compositions XmlDataProvider.

<ListBox x:Name="_compositionList" Margin="40,20" 
         ItemsSource="{Binding Source={StaticResource CompositionData}, XPath=//pc:Compositions/pc:Composition}"/>

That’s it!
restfulclient

Asynchronous Web Service Implementation

In my last post I demonstrated different ways to invoke a web service asynchronously in a WPF smart client application. It’s also possible to implement the service itself using the asynchronous pattern.

For this example I will create a Baroque service. The contract for this service contains two operations: GetComposers and GetCompositions. GetComposers returns a list of Baroque era music composers via an array of Composer types. Composer is declared as a data contract that contains members for a unique numeric id, first, middle and last names.

GetCompositions returns a collection of well known compositions of a given composer. It takes the composer’s numeric id as a parameter and returns an array of string. The service contract would normally be declared as follows for a synchronous implementation.

[ServiceContract(Namespace = "https://patconroy.wordpress.com/service")]
public interface IBaroque
{
    [OperationContract]
    Composer[] GetComposers();

    [OperationContract]
    string[] GetCompositions(int composerId);
}

I’ll demonstrate later that this is how the client will see the service contract, but it must be declared differently on the back-end for asynchronous operation.

[ServiceContract(Namespace="https://patconroy.wordpress.com/service")]
public interface IBaroque
{
    [OperationContract(AsyncPattern=true)]
    IAsyncResult BeginGetComposers(AsyncCallback callback, object asyncState);
    Composer[] EndGetComposers(IAsyncResult result);

    [OperationContract(AsyncPattern=true)]
    IAsyncResult BeginGetCompositions(int composerId, AsyncCallback callback, object asyncState);
    string[] EndGetCompositions(IAsyncResult result);
}

First of all each operation is now implemented as a pair of Begin/End methods and some additional parameters were introduced. This follows the standard .NET asynchronous pattern, so it should look familiar. Additionally the AsyncPattern property of the OperationContract attribute must be set to true.

Since I’m implementing the async pattern rather than just using it I created a helper class that implements the IAsyncResult interface. This will be returned by the two Begin methods and will subsequently be passed back to the End methods. This class can hold and application state data that’s needed between the Begin and End calls. The class also includes a ManualResetEvent that gets set when the asynchronous operation completes

public class AsyncResult : IAsyncResult
{
    private object _state;
    private AsyncCallback _callback;
    private ManualResetEvent _event;

    public AsyncResult(AsyncCallback callback, object state)
    {
        _callback = callback;
        _state = state;
        _event = new ManualResetEvent(false);
    }

    #region IAsyncResult Members
    public object AsyncState
    {
        get { return _state; }
    }

    public WaitHandle AsyncWaitHandle
    {
        get { return _event; }
    }

    public bool CompletedSynchronously
    {
        get { return false; }
    }

    public bool IsCompleted
    {
        get { return _event.WaitOne(0, false); }
    }
    #endregion

    public void Complete()
    {
        _event.Set();
        if (_callback != null)
            _callback(this);
    }
}

To implement this solution I created and Access database named baroque.mdb that has two tables: Composer and Composition. Composer has a unique id column as well as the first, middle and last name text columns. Composition has the composer id and composition name columns. As you might guess there is a one-to-many relationship between composer and composition. This example used the OLE-DB data provider to read the table.

public IAsyncResult BeginGetComposers(AsyncCallback callback, object asyncState)
{
    TypedAsyncResult<Composer&#91;&#93;> result = new TypedAsyncResult<Composer&#91;&#93;>(callback, asyncState);
    ThreadPool.QueueUserWorkItem(new WaitCallback(GetComposers), result);
    return result;
}

public Composer[] EndGetComposers(IAsyncResult result)
{
    TypedAsyncResult<Composer&#91;&#93;> asyncResult = result as TypedAsyncResult<Composer&#91;&#93;>;
    if (result != null)
    {
        asyncResult.AsyncWaitHandle.WaitOne();
        return asyncResult.Result;
    }
    return null;
}

As you can, see the Begin operation sends the work to a background thread. GetComposers isn’t listed here but it’s in the code download. The framework calls the End method. You don’t do that at all. TypedAsyncResult is a specialization of AsyncResult that stores a generic operation result. It’s in the code download. BeginGetCompositions and EndGetCompositions are implemented similarly.

What is the benefit of the extra coding that was done here? For this example there really isn’t one. The OLE-DB data provider only supports synchronous database operations, so I had to create my own background thread. The SQL Server data provider, on the other hand, does support asynchronous operations. Had I used SQL Server instead of Access then I would have used SqlCommand.BeginExecuteReader and SqlCommand.EndExecuteReader. Background threading is handled in the framework rather than in the application.

WCF hides all of these implementation details from the client. The client only sees GetComposers and GetCompositions methods as if they were synchronous implementations. Of course the WCF client proxy can optionally contain the methods needed to call the service asynchronously. I described these in my last post. These are, however, independent of the server implementation. The client can choose to call the service synchronously or asynchronously regardless of how the service was coded. The code download contains a WPF client application that uses the event based asynchronous pattern to call the service.

composerclient

All of the source code from this post can be downloaded here.

Asynchronous Web Service Invocation

In my last post I described various ways to perform work on a background thread in a WPF smart client application. Performing long running operations on the main application thread will freeze the user interface and yield a poor user experience. On the other hand any GUI elements must be manipulated on the main application thread and only on that thread. In this post I describe three different ways to make web service calls on a background thread using WCF client components.

First I created a simple, self-hosted WCF service implementing a simple calculator interface. The Windows SDK has several example implementations of this interface. Each of the implementation methods in my service sleeps for 10 seconds to simulate a long running process.

[ServiceContract(Namespace="https://patconroy.wordpress.com/service")]
public interface ICalculator
{
    [OperationContract]
    double Add(double n1, double n2);
    [OperationContract]
    double Subtract(double n1, double n2);
    [OperationContract]
    double Multiply(double n1, double n2);
    [OperationContract]
    double Divide(double n1, double n2);
}

Those of you running Vista will need to execute the following command as administrator to update the system URL ACL, substituting your own Windows domain and userid in the appropriate place.

netsh http add urlacl url=http://+:8000/ user=domain\userid

The client application example presents four different ways of calling the web service. The main windows has four radio buttons to select from amongst them.

  1. Synchronously on the GUI thread
  2. Asynchronously using BackgroundWorker
  3. Using the Asynchronous Programming Model
  4. Using a new .NET 3.5 event based model

The first of these is certainly the easiest to code. All work occurs on the main application thread, but herein lies a problem. The user interface is frozen while the application waits for the web service to return.

Using BackgroundWorker

The second technique is certainly an improvement. BackgroundWorker is used to launch a background thread that makes the web service call. The background thread waits for the web service to return then sets DoWorkEventArgs.Result. This Result is handed to the RunWorkerCompleted delegate on the GUI thread.

private static void CallServiceBackgroundWorker(Window1 win, double n1, double n2)
{
    BackgroundWorker bw = new BackgroundWorker();
    bw.DoWork += BackgroundWorker_DoWork;
    bw.RunWorkerCompleted += win.BackgroundWorker_RunWorkerCompleted;
    bw.RunWorkerAsync(win);
}
// BackgroundWorker callbacks
static void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
    Window1 win = (e.Argument) as Window1;
    e.Result = _calcClient.Add(win._data.Number1, win._data.Number2);
}
void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // This callback is made on the GUI thread
    UpdateResult((double)e.Result);
}

Do you see a problem here? Earlier I stated that “The background thread waits for the web service.” The application consumes a background thread while waiting for the web service to finish. This background thread could be utilized for something else while the web service call is outstanding. This isn’t a problem in a small example but could be a scalability killer in a larger real-world application.

Using the Asynchronous Programming Model

This last problem is solved by the Asynchronous Programming Model. The APM pervades the .NET framework. One can, for example, read a FileStream using this method. It works roughly like this.

void CallServiceAsyncPattern(Window1 win, double n1, double n2)
{
    IAsyncResult ar = obj.BeginXyz(param, new AsyncCallback(MyCallback), state);
}
void MyCallback(IAsyncResult ar)
{
    var result = obj.EndXyz(ar);
}

The names of the Begin and End methods will of course differ from class to class. The main application thread initiates the asynchronous operation by calling BeginXyz(). The framework itself then performs the operation on a background thread or better yet by using overlapped I/O. Overlapped I/O is a Windows OS feature that completes the I/O operation in the Windows kernel. An application callback is called when the operation completes. The callback occurs on a background thread.

The .NET web service proxy generator creates a Begin and End method for each of the service interface methods when the /async command line option is specified.

svcutil http://localhost:8000/service/calculator/mex /async

Or just check “Generate asynchronous operations” when creating a service reference in Visual Studio. This example client uses BeginAdd and EndAdd. AsyncCallback is called on a background thread when the web service operation completes. AsyncCallback cannot access the GUI directly, so it dispatches the result to the GUI thread.

private delegate void UpdateResultDelegate(double n);
private static void AsyncCallback(IAsyncResult ar)
{
    double result = _calcClient.EndAdd(ar);
    Window1 win = (ar.AsyncState as Window1);
    // Result must be dispatched to the GUI thread
    win.Dispatcher.Invoke(new UpdateResultDelegate(win.UpdateResult), result);
}
private static void CallServiceAsyncPattern(Window1 win, double n1, double n2)
{
    IAsyncResult ar = _calcClient.BeginAdd(n1, n2, AsyncCallback, win);
}

Using an event based model

A new event based asynchronous model was introduced in the framework version 3.5. The service proxy generator creates all the necessary delegate declarations and event argument classes. It also adds a completed event and an XyzAsync() method to the proxy class for each of the web service methods. Specify /tcv:version35 in addition to /async on the svcutil command line to generate this additional code. This is also done automatically in Visual Studio when “Generate asynchronous operations” is checked.

The event model is an improvement over APM because the completed event is called on the same thread that initially made the asynchronous service request. In the example here AddAsync() is called on the GUI thread, so the AddCompleted event handler is called on the GUI thread after the web service returns. The need to dispatch the result to the GUI thread has been eliminated. GUI state can be manipulated within the event handler, so coding is much easier than with APM.

Event handlers must be set on the service proxy instance prior to making any service requests. This example only uses the Add service method, so only an AddCompleted event handler is set. CalculatorClient also includes SubtractCompleted, MultiplyCompleted and DivideCompleted event handlers.

private static CalculatorClient _calcClient;
static Window1()
{
    _calcClient = new CalculatorClient();
    _calcClient.AddCompleted +=new EventHandler<AddCompletedEventArgs>(CalcClient_AddCompleted);
}
private static void CalcClient_AddCompleted(object sender, AddCompletedEventArgs e)
{
    // This callback is made on the GUI thread
    (e.UserState as Window1).UpdateResult(e.Result);
}

Initiating an asynchronous call to Add is simply a matter of calling CalculatorClient.AddAsync(). Note that the code generator also created SubtractAsync, MultiplyAsync and DivideAsync methods.

private static void CallServiceNewAsync(Window1 win, double n1, double n2)
{
   _calcClient.AddAsync(n1, n2, win);
}

All source code for this example is located here.

Background Threads in WPF

Anyone writing smart client applications will eventually run into a situation where some work must be performed asynchronously on a background thread. Long running computations, database access, web service calls and large file I/O are all good candidates. Any long-running operation must be performed on a background thread to avoid freezing the user interface. More often than not the UI state needs to change after the background operation completes. Perhaps the UI must show feedback as the operation executes – think progress bar. It would be great to update the UI right from the background thread, but WPF has strict rules concerning threading.

There’s one rule really, but it’s important and will drive how you design the background thread to UI conversation. WPF UI elements must be manipulated only on the UI thread. This rule pertains to instances of any class that inherits directly or indirectly from DispatcherObject, and this means all UI elements.

So you can’t set TextBox.Text or TreeViewItem.Header from any but the UI thread, is that it? Well, not exactly. Data binding complicates things. I’ve created a sample program where a ListBox is bound to an ObservableCollection. With this binding in place any changes to the collection indirectly manipulate the ListBox. Recall that ObservableCollection raises the CollectionChanged event whenever the items list changes. The ListBox, or more accurately a CollectionView that the framework inserts between the ListBox and bound collection, handles his event. CollectionChanged is raised synchronously on whatever thread modified the collection. When performed on any other than the UI thread a NotSupportedException is raised. You can see this in action by clicking on the button labeled “Kaboom!” in the sample program.

wpfthreads

Here’s the code that executes when “Kaboom!” is clicked.

private void Kaboom_Click(object sender, RoutedEventArgs e)
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(KaboomThreadProc), this);
}
static void KaboomThreadProc(object sender)
{
    Window1 win = sender as Window1;
    string item = GetNextItem();
    // Sleep to simulate a long running process
    Thread.Sleep(1000);
    win.AddItem(item);
}

WPF provides the Dispatcher class to route work back to the UI thread. A Dispatcher object is created on the UI thread when the application starts up. Work can be sent to the UI thread by using this Dispatcher object and it’s Invoke or BeginInvoke methods. Invoke executes the work synchronously while BeginInvoke is asynchronous. This Dispatcher object is accessed in several ways. The static Dispatcher.CurrentDispatcher property will return it when called on the UI thread. Every DispatcherObject keeps a reference to the Dispatcher from the thread on which it was created. In other words every UI element has a Dispatcher property that returns the UI thread’s Dispatcher object. The current example used the Window’s Dispatcher in order to update the ObservableCollection on the UI thread. Click the button labeled “Dispatcher” to execute this code which updated the ListBox successfully.

private delegate void AddItemDelegate(string item);
private void AddItem(string item)
{
    _coll.Add(item);
}
 static void DispatcherThreadProc(object sender)
{
    Window1 win = sender as Window1;
    string item = GetNextItem();
    // Sleep to simulate a long running process
    Thread.Sleep(1000);
    win.Dispatcher.Invoke(DispatcherPriority.Normal,
        new AddItemDelegate(win.AddItem), 
        item);
}

Note that Dispatcher is a priority based queue of work items that get executed as the thread’s message pump processes Windows messages. Here the sample invokes a delegate on the UI thread at Normal priority, but other higher or lower priorities could have been used.

BackgroundWorker, a holdover from Windows Forms, may also be used as it fires its RunWorkerCompleted event on the UI thread. Perform some background work in the DoWorkEventHandler delegate. The DoWorkEventArgs parameter that the delegate receives contains Result property that should be set to the result of the background operation. The Result is passed to the RunWorkerCompletedEventHandler delegate so that it may be used on the UI thread to update the UI state. Click the button labeled “BG Worker” to update the ListBox using this method.

private void BGWorker_Click(object sender, RoutedEventArgs e)
{
    BackgroundWorker bgWorker = new BackgroundWorker();
    bgWorker.DoWork += new DoWorkEventHandler(BGWorker_DoWork);
    bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BGWorker_RunWorkerCompleted);
    bgWorker.RunWorkerAsync(this);
}
static void BGWorker_DoWork(object sender, DoWorkEventArgs e)
{
    string item = GetNextItem();
    // Sleep to simulate a long running process
    Thread.Sleep(1000);
    e.Result = item;
}
void BGWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    AddItem(e.Result as string);
}

Source code for this sample may be downloaded here.

More on XML Data Binding

In my last post I demonstrated how to bind elements from an XML document to WPF controls. I created small master/detail dual pane application to demonstrate this. Here I continue exploring XML data binding using the same XML document but with these important differences.

  1. The XML document will use namespaces.
  2. The data will be sorted in a different order.
  3. The view of the data will be flattened into a ListView.

Using XML Namespaces

Adding a namespace to the XML document itself is a simple matter. Once this is done, however, changes must be made to the code that accesses the now namespace scoped XML elements and attributes. First, here’s the updates XML document.

<pc:States xmlns:pc="https://patconroy.wordpress.com/States/">
    <pc:State pc:Name="Delaware" pc:Abbrev="DE">
        <pc:Capital>Dover</pc:Capital>
        <pc:Nickname>The First State</pc:Nickname>
        <pc:Bird>Blue Hen Chicken</pc:Bird>
        <pc:Flower>Peach Blossom</pc:Flower>
        <pc:Tree>American Holly</pc:Tree>
        <pc:Motto>Liberty and Independence</pc:Motto>
    </pc:State>
    <!-- Other states omitted for brevity -->
</pc:States>

The application no longer displays the data after making this change. It turns out that two changes must be made to the XAML source. First an XmlNamespaceMappingCollection must be associated with the XmlDataProvider. The XmlNamespaceMappingCollection creates a mapping between namespace URIs and their prefixes that are later used in XPath expressions. The XmlDataProvider.XmlNamespaceManager property must be set to an instance of XmlNamespaceMappingCollection. Here I create a mapping between the prefix “pc” and my namespace URI http://patconroy.workpress.com/States/.

<XmlNamespaceMappingCollection x:Key="StateDataNamespaceMapping">
    <XmlNamespaceMapping Uri="https://patconroy.wordpress.com/States/" Prefix="pc" />
</XmlNamespaceMappingCollection>
<XmlDataProvider x:Key="StateData" XmlNamespaceManager="{StaticResource StateDataNamespaceMapping}">
    <!-- etc. -->
</XmlDataProvider>

Next the XPath expressions used in the application must be updated to use the “pc” prefix. Without the prefix the XPath processor looks for elements and attributes in the global namespace, and this in no longer the case. The state XPath expression to access the state collection now becomes //pc:States/pc:State instead of //States/State. The expression to access the Name attribute of the State element now becomes @pc:Name.

Sorting the Data

In the XML document the states are presented in the order in which they ratified the Constitution for the United States of America. Any ItemsControl, including the ListBox used in the last example and the ListView used here, will display them in this order when bound to the XmlElement collection returned by the XPath expression //pc:States/pc:State. In this application I want them alphabetized by state abbreviation. WPF includes the CollectionViewSource class to do exactly this. CollectionViewSource can also do grouping and filtering. Check MSDN for the details. Here I create a CollectionViewSource in the main window’s resource dictionary to sort on the Abbrev XML attribute.

<CollectionViewSource x:Key="StateViewSource" Source="{Binding Source={StaticResource StateData},XPath=//pc:States/pc:State}">
    <CollectionViewSource.SortDescriptions>
        <cm:SortDescription PropertyName="@pc:Abbrev"/>
    </CollectionViewSource.SortDescriptions>
</CollectionViewSource>

The CollectionViewSource binds to the XmlDataProvider and applies an XPath expression to access the collection of State elements. A SortDescription is added to sort on the Abbrev attribute, which is again accessed using an XPath expression. The SortDescription class doesn’t exist in any of the default XAML namespaces, so the namespace declaration xmlns:cm="clr-namespace:System.ComponentModel;assembly=WindowsBase" must be added to the XAML. The ItemsControl displaying this data must bind to the CollectionViewSource, not the XmlDataProvider: ItemsSource="{Binding Source={StaticResource StateViewSource}}".

Displaying in a ListView

In previous posts I re-templated the ListView control. As part of this I implemented alternating row colors to achieve an accounting ledger look. The accounting ledger look can be achieved far more simply than this; it isn’t necessary to re-template the entire control. When working with .Net 3.5 SP1 apply the AlternationCount attribute to the ListView itself. Then add an ItemContainerStyle containing the property triggers on ItemsControl.AlternationIndex as shown in the previous post. I had to create a DataTemplate for the first column in order to display the state flag there. A value converter is used to obtain the image file path. Thanks again to folks at 3DFlags.com for the flag images. Here’s the complete ListView XAML for this project.

<ListView x:Name="_stateList" Margin="4"
          AlternationCount="2"
          ItemsSource="{Binding Source={StaticResource StateViewSource}}">
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Style.Triggers>
                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                    <Setter Property="Background" Value="Khaki"/>
                </Trigger>
                <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                    <Setter Property="Background" Value="Beige"/>
                </Trigger>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="LightBlue"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListView.ItemContainerStyle>
    <ListView.View>
        <GridView AllowsColumnReorder="true">
            <GridViewColumn Width="36">
                <GridViewColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="{Binding XPath=@pc:Abbrev, Converter={StaticResource ImageNameConverter}}"/>
                    </DataTemplate>
                </GridViewColumn.CellTemplate>
            </GridViewColumn>
            <GridViewColumn Width="48" DisplayMemberBinding="{Binding Path=@pc:Abbrev}" Header="Abbrev"/>
            <GridViewColumn Width="100" DisplayMemberBinding="{Binding Path=@pc:Name}" Header="Name"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Nickname}" Header="Nickname"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Capital}" Header="Capltal City"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Bird}" Header="State Bird"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Flower}" Header="State Flower"/>
            <GridViewColumn Width="120" DisplayMemberBinding="{Binding XPath=pc:Tree}" Header="State Tree"/>
            <GridViewColumn Width="200" DisplayMemberBinding="{Binding XPath=pc:Motto}" Header="Motto"/>
        </GridView>
    </ListView.View>
</ListView>

Here’s how the finished application looks.
xmllistview

Source code can be downloaded here.


October 2017
M T W T F S S
« Apr    
 1
2345678
9101112131415
16171819202122
23242526272829
3031  
I am a part of all that I have met;
Yet all exprience is an arch whitherthro'
Gleams that untravell'd world, whose margin fades
For ever and for ever when I move.
How dull it is to pause, to make an end,
To rust unburnish'd, not to shine in use!
Alfred, Lord Tennyson