Category Archives: WPF

WPF databinding trick (part 1)

The last week, one of my colleague was doing a WPF training session and she ended up having a very strange behavior with the WPF databinding engine. I’ll describe a not well-known behavior of the WPF databinding engine and I’ll try to explain how its works under the scene.

Binding the Text property of a TextBlock to a collection of objects

This is something you’re not supposed to do, but you’ll see it actually works in an unexpected way. In the code-behind of our Window, we have the following C# code:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
            
        Person person1 = new Person { Age = 45 };
        Person person2 = new Person { Age = 63 };
        Person person3 = new Person { Age = 71 };

        this.DataContext = new List { person1, person2, person3 };
    }
}

public class Person
{
    public int Age
    {
        get;
        set;
    }
}

The associated XAML looks like the following:


 
    
        
    

Here we’re doing something not usual: we’re binding the Text property of the TextBlock (which is of type string) to a collection of objects.

What do you think the Window will display ?

The first time I saw this code, I thought the Window will remain empty. The DataContext is set to a List and we’re trying to find an “Age” property on this collection: THAT CANNOT WORK.

Actually, it does…

What’s happening behind the scene ?

Let’s take a deep breath a take a look at what’s happening behind the scene to make this works.

1. A CollectionView is created

The first thing I was thinking while talking about the problem with my colleague was the use of a collection view. As you probably now, every time you create a binding to a collection property, the engine creates a collection view for you. This view will serve as an intermediate layer between your source and the target to manage selection, filtering and grouping. A good introduction to collection views is available here.

What is important to know is that collection views are shared along same objects instance. It means that when you use the CollectionViewSource.GetDefaultView() method, you’re either creating a default view for the collection (if no one has requested one before) or getting the default view (if it has been created by calling the same method before you).

To make sure I was right about my hypothesis, I added the following code in the C#:

var collectionView = CollectionViewSource.GetDefaultView(this.DataContext);
collectionView.MoveCurrentToNext();
this.MouseDoubleClick += (s, e) => collectionView.MoveCurrentToNext();

And the Window is now displaying the second item of the list:

So we’re definitively dealing with a collection view. The next question was, where the value comes from, I specified “Age” as binding path…

2. The CurrentItem property of ICollectionView

If you take a look at the documentation about ICollectionView, you’ll find this property:

So it looks like the Text property of my TextBlock is databound to this CurrentItem property while I explicitly set to the Age property…

3. The magic of the PropertyPathWorker class

Using Reflector, I looked for potential types using the ICollectionView.CurrentItem property. I found an interesting class: PropertyPathWorker.In the source code of the .Net framework, this type is defines as “the workhorse for CLR binding“.

In particular, take a look at this method:

private void ReplaceItem(int k, object newO, object parent)
{
    // some code...

    view = CollectionViewSource.GetDefaultCollectionView(parent, TreeContext);

    // some more code...

    newO = view.CurrentItem;
    if (newO != null)
    {
        GetInfo(k, newO, ref svs);
        svs.collectionView = view;
    } 

    // and bam ! we're now using view.CurrentItem as source for our binding
}

So we’ve a special case when we’re creating a binding with a collection view: the CurrentItem property is automatically used and merge with the specificied path. In our case, it’s like creating a binding to CurrentItem.Age.

3. And voila !

Finally we’ve a lot going on within the engine to make this works. Of course the original binding was not something we would do in normal application but it was kind of cool doing the investigations to find out why it was working ! Hope you learn something cool about the databinding engine 🙂

Next week I’ll try to write a similar article about another strange behavior you might have already seen…

 

Visual Studio 2010 and HW acceleration on Windows XP…

Last week during the MVP summit in Seattle we’d the confirmation that the SP1 of Visual Studio was almost ready and today we’ve more details: “Visual Studio 2010 Service Pack 1 will be available March 9th for download for MSDN Subscribers, and will be generally available for download on March 10th, 2011” [from G.Duthie’s blog on MSDN].

“While the Service Pack is mostly focused on improvements in response to feedback on Visual Studio 2010, one new feature I want to highlight is the integration of IIS Express into Visual Studio 2010. IIS Express, which was introduced with the new Microsoft WebMatrix editor, is a lightweight, yet full-featured version of IIS that can run without administrative permissions.”

Another important thing to notice about the SP1, is that it will disable the hardware acceleration of the IDE on Windows XP. Yes, you read correctly, despite WPF’s support for accelerated graphics, this feature will be disabled on XP (for VS only).

Background

When the version 3.5 of the .Net framework was released, Microsoft added a new software rendering engine in case the hardware was not able to do the job. This feature could be enabled at the Window level using the following code:

HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
HwndTarget hwndTarget = hwndSource.CompositionTarget;
hwndTarget.RenderMode = RenderMode.SoftwareOnly;

With WPF4, this is now possible at the Process level using a single line of code:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly

Another trick you can use in your application is to determine whether your application is currently using hardware acceleration. You can do that by looking at the RenderCapability.Tier enumeration.

In your applications running on XP…

Now the immediate question that might come in your mind is: “If VS2010 is disabling HW acceleration on XP, should I do the same on my WPF application which is shipped on XP too ?”

I guess the answer is “maybe” and it actually depends on various factors:

  • does your user reported crash that seems correlated to video drivers issue ?
  • does your application extensively uses complex graphical effects (for example this is clearly not the case in VS2010) ?
  • what kind of hardware your users are using. Is this recent hardware (which are being downgraded to XP) or is this really old hardware ?

Maybe a good option is to let the user change this settings (while having a default value). In VS2010, you’ll be able to turn on HW acceleration back by using the settings dialog:


Anyway, I thought at the beginning it was a very weird decision. But after all; if the majority of the crashes they see in VS on Windows XP is linked to bad drivers, it makes sense.

TechDays 2011: Rx talk, slides and source code

As promised, here is a blog post which shares source code and slides for the Rx talk I gave during last TechDays in Paris. I animated this session with my co-worker Charlotte and with Mitsu.

Download slides here.
Download source code here.

Demo1: Drag’n’drop in a WPF application

The goal was to implement a basic drag’n’drop functionality in a WPF application. The Rx query looks like the following:

var query = from mouseDown in this.image.GetMouseLeftButtonDownObservable()
            let downPosition = mouseDown.EventArgs.GetPosition(this)
            let rect = new Rect(downPosition.X - 10, downPosition.Y - 10, 20, 20)
            let delta = mouseDown.EventArgs.GetPosition(this.image)
            from mouseMove in this.GetMouseMoveObservable()
                .Select(ea => ea.EventArgs.GetPosition(this))
                .SkipWhile(p => rect.Contains(p))
                .DoOnce(p => this.onMouseEnter.Begin(this.image))
                .Select(p => p.Offset(delta))
                .TakeUntil(this.GetMouseLeftButtonUpObservable())
                .Finally(() => this.onMouseLeave.Begin(this.image))
            select mouseMove;

query.Subscribe(p => this.image.SetPosition(p));

Demo2: online Twitter search and Bing map geolocalization

This time, the goal was to query Twitter asynchronously and to geolocalize the associated Tweets. The Rx query:

this.textbox.GetTextChangedObservable()
    .DistinctUntilChanged((ea) => this.textbox.Text)
    .Throttle(TimeSpan.FromMilliseconds(300))
    .ObserveOnDispatcher()
    .Do(ea => this.ShowLoadingIndicator())
    .Select(ea => TweeterHelper.Search(this.textbox.Text))
    .Switch()
    .ObserveOn(Scheduler.Dispatcher)
    .Select(page => TweeterHelper.ParseTwitterSearch(page))
    .Subscribe((tweets) =>
                    {
                        this.HideLoadingIndicator();
                        this.listbox.ItemsSource = tweets;

                        TweeterHelper.LocalizeTweets(this.map, tweets);
                    });

Demo3: using the accelerometer in a Windows Phone 7 application

The last demo was about the usage of the accelerometer in a Windows Phone 7 application. Here is the relevant Rx query:

private void MoveEllipse(IObservable accelerationObservable)
{
    accelerationObservable
        .SlidingBuffer(2)
        .Select(accCouple => new Acceleration(accCouple.First(), accCouple.Last()))
        .ObserveOnDispatcher()
        .Do(acc => this.textBlock.Text = acc.ToString())
        .Scan(new Point(x0, y0), (point, acc) => point.Move(acc).ClipTo(horizontalInterval, verticaInterval))
        .Subscribe(p => this.ellipse.SetCenter(p));
}

Doing this session was a really great experience ! I’d like to thank Charlotte and Mitsu for doing it with me. Also, I’d like to thank all users who came to the presentation !