Skip to main content

C# WPF Tutorial - Priority Bindings [Beginner]


Bindings, bindings, bindings. WPF is all about bindings - and you can't be all about bindings unless there are a whole bunch of different types to play with. We have looked at a couple different types here - I won't list them all, it is probably just easier to look at list in the WPF category. Today we are going to introduce yet another type of binding - the Priority Binding.

What is a priority binding, you ask? Well, it is a binding with a number of possible sources, with the sources ordered by priority. The source with the highest priority that returns a value successfully becomes the active binding in a priority binding. The key here, though, is that the active binding can change. If a low priority source returns first, it will become the active binding. But as soon as a source with higher priority returns successfully, it will supersede the lower priority source and become the active binding.

You are probably wondering about how this is actually useful. Well, there is a great example for this - take Microsoft Word. When you open a document in Word, there is a page count displayed in the bottom status bar. If you've ever opened a really long document in Word, you may have noticed that that page count is not actually correct until the document finishes loading - for a couple seconds, it shows an approximate page count that keeps changing. This is a perfect use of a priority binding. The slowest, but highest priority binding would return the correct number of pages - but there would also be a fast, low priority binding that would return the approximate number of pages. The software would use the fast low priority method until the slow, high priority method finally returned with a value. Pretty much, priority bindings can be useful whenever there is something slow and asynchronous that is affecting your UI.

Enough with this talk - lets look at some code!
<Window x:Class="PriorityBindingTest.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Priority Binding Test" Height="100" Width="200"
    Name="MainWindow">
  <Grid>
    <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
      <TextBlock.Text>
        <PriorityBinding>
          <Binding ElementName="MainWindow" Path="Slow" IsAsync="True" />
          <Binding ElementName="MainWindow" Path="Medium" IsAsync="True" />
          <Binding ElementName="MainWindow" Path="Fast" />
        </PriorityBinding>
      </TextBlock.Text>
    </TextBlock>
  </Grid>
</Window>
 
OK, here we have a simple window defined in XAML, with a single TextBlock. It is the content of the TextBlock that we are interested in, because that is where the PriorityBinding is. To use a priority binding, you make a PriorityBinding where you would usually make a regular binding, and then fill the PriorityBinding with other bindings. The order of the other bindings here is very important - the order determines priority. The first binding in the list has the highest priority, and the second has the second highest, and so on and so forth. Here we have three bindings, each to a different path: Slow, Medium, and Fast. The slow one will obviously be the slowest (because we are going to code it that way), but seeing that it comes first, it has the highest priority.

There is one important flag on some of these bindings that you may not recognize: IsAsync="True". This is actually very important - without it, priority bindings wouldn't be very useful. Essentially, it means "go try and get that value asynchronously". We don't want the main thread to try and determine the value for the slow or medium binding - because if it did, the app would just sit there as the main thread tried to resolve the binding. It would make the priority pointless, because the application would sit and process the highest priority binding, ignoring everything else until the binding returned a value.

But with that IsAsync flag, the main application thread tells a thread pool thread to go off and process that binding - leaving the main thread free to continue on. So in a priority binding, everything but the lowest priority (and hopefully fastest) binding should be set to async. The reason that we don't set the last binding to async is that we generally want to return at least some value for the binding immediately. You can set the last binding to async if it also takes some time - this just means that there will be a period of time where this binding has no value.

OK, now for the C# code for the properties these three bindings are hitting against:
public string Slow
{
  get
  {
    Console.WriteLine("Slow: " + Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(2000);
    return "This is the slowest value.  I'm so slow.";
  }
}

public string Medium
{
  get
  {
    Console.WriteLine("Medium: " + Thread.CurrentThread.ManagedThreadId);
    Thread.Sleep(1000);
    return "Medium! Medium! Woohoo!";
  }
}

public string Fast
{
  get
  {
    Console.WriteLine("Fast: " + Thread.CurrentThread.ManagedThreadId);
    return "Wow, this is fast!";
  }
}
 
Essentially, all we are doing here is sleeping the slow and medium for a few seconds before returning the value. And just to prove that the requests are actually coming in off of separate threads, I threw in some Console.Writeline calls printing out the the thread ids:
Slow: 7
Fast: 10
Medium: 11
 
And in fact, if you look at more of the details about the threads hitting the property values, you will find that the thread hitting Fast is in fact the main application thread, and the threads hitting Slow and Medium are background worker thread pool threads.

So, in the end, the application transitions through three states that look like this:

Three states of the binding

The application initially looks like the first window. After a second, the text changes to what is displayed in the second window. And after another second, the Slow binding finally kicks in, and the text changes to what is in the third window

And there you go - that is it for an introduction to priority bindings! You can download the source for this simple Visual Studio project here, if you would like to play around with it. 

Source Files:

Comments

Popular posts from this blog

C# Snippet - Shuffling a Dictionary [Beginner]

Randomizing something can be a daunting task, especially with all the algorithms out there. However, sometimes you just need to shuffle things up, in a simple, yet effective manner. Today we are going to take a quick look at an easy and simple way to randomize a dictionary, which is most likely something that you may be using in a complex application. The tricky thing about ordering dictionaries is that...well they are not ordered to begin with. Typically they are a chaotic collection of key/value pairs. There is no first element or last element, just elements. This is why it is a little tricky to randomize them. Before we get started, we need to build a quick dictionary. For this tutorial, we will be doing an extremely simple string/int dictionary, but rest assured the steps we take can be used for any kind of dictionary you can come up with, no matter what object types you use. Dictionary < String , int > origin = new Dictionary < string , int >(); ...

C# WPF Printing Part 2 - Pagination [Intermediate]

About two weeks ago, we had a tutorial here at SOTC on the basics of printing in WPF . It covered the standard stuff, like popping the print dialog, and what you needed to do to print visuals (both created in XAML and on the fly). But really, that's barely scratching the surface - any decent printing system in pretty much any application needs to be able to do a lot more than that. So today, we are going to take one more baby step forward into the world of printing - we are going to take a look at pagination. The main class that we will need to do pagination is the DocumentPaginator . I mentioned this class very briefly in the previous tutorial, but only in the context of the printing methods on PrintDialog , PrintVisual (which we focused on last time) and PrintDocument (which we will be focusing on today). This PrintDocument function takes a DocumentPaginator to print - and this is why we need to create one. Unfortunately, making a DocumentPaginator is not as easy as...

C# WPF Tutorial - Implementing IScrollInfo [Advanced]

The ScrollViewer in WPF is pretty handy (and quite flexible) - especially when compared to what you had to work with in WinForms ( ScrollableControl ). 98% of the time, I can make the ScrollViewer do what I need it to for the given situation. Those other 2 percent, though, can get kind of hairy. Fortunately, WPF provides the IScrollInfo interface - which is what we will be talking about today. So what is IScrollInfo ? Well, it is a way to take over the logic behind scrolling, while still maintaining the look and feel of the standard ScrollViewer . Now, first off, why in the world would we want to do that? To answer that question, I'm going to take a an example from a tutorial that is over a year old now - Creating a Custom Panel Control . In that tutorial, we created our own custom WPF panel (that animated!). One of the issues with that panel though (and the WPF WrapPanel in general) is that you have to disable the horizontal scrollbar if you put the panel in a ScrollV...