Click here to Skip to main content
15,902,112 members
Articles / Desktop Programming / WPF

WPF: Passing Data to Sub-Views via DataContext Causes Trouble

Rate me:
Please Sign up or sign in to vote.
4.25/5 (3 votes)
16 Dec 2010Apache2 min read 19.5K   3   2
WPF: Passing Data to Sub-Views via DataContext Causes Trouble

Imagine I have a main view that contains a number to sub-views. To be concrete, let’s assume that the sub-view is a user control of type PersonView that displays person’s information.

How do you tell the PersonView what person to display? Passing it via DataContext seems like a natural choice, so the XAML looks something like this:

XML
<StackPanel ...>
   <my:PersonView DataContext={Binding PersonA} />
   <my:PersonView DataContext={Binding PersonB} />
</StackPanel>

This is all fine until I try to set other properties of PersonView, e.g.

XML
<my:PersonView Visibility={Binding IsPersonAVisible} DataContext={Binding PersonA} />

The IsPersonAVisible binding does not work. The system first binds the DataContext property to the PersonA object, and then all other bindings are processed against PersonA. Since PersonA does not have "IsPersonAVisible", the binding fails.

Microsoft representatives confirm this and provide some explanation why it should be so, but personally I think it does not sound very convincing.

We can make the binding work by diverting it away from the redirected DataContext, e.g. by specifying ElementName:

XML
<my:PersonView
    Visibility={Binding DataContext.IsPersonAVisible, ElementName=MainWindow}
    DataContext={Binding PersonA} />

But it looks very ugly and long.

We have two ways to avoid this ugliness:

  • Move the properties into the PersonA object
  • Use property other than DataContext to pass person information

The former does not really solve the problem. Even if we have PersonA.IsVisible, it most likely will depend on some external data, and we will need to write code to set it duplicating the work the binding would do for us.

The latter wrecks havoc in the bindings of the PersonView itself, but this can be rectified. When we passed person information via DataContext, the PersonView looked probably something like this:

XML
<UserControl ...>
    <StackPanel>
        <TextBlock Text="{Binding FirstName}" />
        <TextBlock Text="{Binding LastName}" FontWeight="Bold" />
    </StackPanel>
</UserControl>

If we now pass person information in control property like Person, all bindings will stop working. We can fix it by setting DataContext on the main visual, so it can done only once:

XML
<UserControl ...>
    <StackPanel DataContext="{Binding Person, 
	RelativeSource={RelativeSource AncestorType=UserControl}}">
        <TextBlock Text="{Binding FirstName}" />
        <TextBlock Text="{Binding LastName}" FontWeight="Bold" />
    </StackPanel>
</UserControl>

Now, things are back to normal, and we have only one ugly binding. Note that setting data context on the user control itself won't help, because it will lead to the same problem as before.

This article was originally posted at http://www.ikriv.com/blog?p=751

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Technical Lead Thomson Reuters
United States United States
Ivan is a hands-on software architect/technical lead working for Thomson Reuters in the New York City area. At present I am mostly building complex multi-threaded WPF application for the financial sector, but I am also interested in cloud computing, web development, mobile development, etc.

Please visit my web site: www.ikriv.com.

Comments and Discussions

 
GeneralMy vote of 3 Pin
SledgeHammer0116-Dec-10 19:38
SledgeHammer0116-Dec-10 19:38 
GeneralInteresting article: thanks for pointing to the issue and resolution. 5 Pin
DrABELL16-Dec-10 19:03
DrABELL16-Dec-10 19:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.