
{"id":751,"date":"2010-12-02T16:53:27","date_gmt":"2010-12-02T21:53:27","guid":{"rendered":"http:\/\/www.ikriv.com\/blog\/?p=751"},"modified":"2010-12-02T16:53:27","modified_gmt":"2010-12-02T21:53:27","slug":"wpf-passing-data-to-sub-views-via-datacontext-causes-trouble","status":"publish","type":"post","link":"https:\/\/ikriv.com\/blog\/?p=751","title":{"rendered":"WPF: Passing Data to Sub-Views via DataContext Causes Trouble"},"content":{"rendered":"<p>Imagine I have a main view that contains a number to sub-views. To be concrete, let&#8217;s assume that the sub-view is a user control of type <code>PersonView<\/code> that displays person&#8217;s information.<\/p>\n<p>How do you tell the <code>PersonView<\/code> what person to display? Passing it via <code>DataContext<\/code> seems like a natural choice, so the XAML looks something liek this:<\/p>\n<pre><code>&lt;StackPanel ...&gt;\n   &lt;my:PersonView DataContext={Binding PersonA} \/&gt;\n   &lt;my:PersonView DataContext={Binding PersonB} \/&gt;\n&lt;\/StackPanel&gt;<\/code><\/pre>\n<p>This is all fine until I try to set other properties of <code>PersonView<\/code>, e.g.<\/p>\n<p><code>&lt;my:PersonView Visibility={Binding IsPersonAVisible} DataContext={Binding PersonA} \/&gt;<\/p>\n<p>The <code>IsPersonAVisible<\/code> binding does not work. The system first binds the <code>DataContext<\/code> property to the <code>PersonA<\/code> object, and then all other bindings are processed against <code>PersonA<\/code>. Since <code>PersonA<\/code> does not have \"IsPersonAVisible\", the binding fails.<\/p>\n<p>Microsoft representatives <a href=\"http:\/\/social.msdn.microsoft.com\/Forums\/en-US\/wpf\/thread\/3e19c180-5439-477e-a27f-7f2018af7828\">confirm this and provide some explanation why it should be so<\/a>, but personally I think it does not sound very convincing.<\/p>\n<p>We can make the binding work by diverting it away from the redirected <code>DataContext<\/code>, e.g. by specifying ElementName:<\/p>\n<pre><code>&lt;my:PersonView\n    Visibility={Binding DataContext.IsPersonAVisible, ElementName=MainWindow}\n    DataContext={Binding PersonA} \/&gt;<\/code><\/pre>\n<p>but it looks very ugly and long.<\/p>\n<p>We have two ways to avoid this ugliness:<br \/>\n- move the properties into the <code>PersonA<\/code> object<br \/>\n- use property other than <code>DataContext<\/code> to pass person information.<\/p>\n<p>The former does not really solve the problem. Even if we have <code>PersonA.IsVisible<\/code>, 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.<\/p>\n<p>The latter wrecks havoc in the bindings of the <code>PersonView<\/code> itself, but this can be rectified. When we passed person information via <code>DataContext<\/code>, the <code>PersonView<\/code> looked probably something like this:<\/p>\n<pre><code>&lt;UserControl ...&gt;\n    &lt;StackPanel&gt;\n        &lt;TextBlock Text=\"{Binding FirstName}\" \/&gt;\n        &lt;TextBlock Text=\"{Binding LastName}\" FontWeight=\"Bold\" \/&gt;\n    &lt;\/StackPanel&gt;\n&lt;\/UserControl&gt;<\/code><\/pre>\n<p>If we now pass person information in control property like <code>Person<\/code>, all bindings will stop working. We can fix it by setting <code>DataContext<\/code> on the main visual, so it can done only once:<\/p>\n<pre><code>&lt;UserControl ...&gt;\n    &lt;StackPanel <b>DataContext=\"{Binding Person, RelativeSource={RelativeSource AncestorType=UserControl}}\"<\/b>&gt;\n        &lt;TextBlock Text=\"{Binding FirstName}\" \/&gt;\n        &lt;TextBlock Text=\"{Binding LastName}\" FontWeight=\"Bold\" \/&gt;\n    &lt;\/StackPanel&gt;\n&lt;\/UserControl&gt;<\/code><\/pre>\n<p>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.<br \/>\n<a style=\"display:none\" href=\"http:\/\/www.codeproject.com\/script\/Articles\/BlogFeedList.aspx?amid=1181663\" rel=\"tag\">CodeProject<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Imagine I have a main view that contains a number to sub-views. To be concrete, let&#8217;s assume that the sub-view is a user control of type PersonView that displays person&#8217;s <a href=\"https:\/\/ikriv.com\/blog\/?p=751\" class=\"more-link\">[&hellip;]<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"Layout":"","footnotes":""},"categories":[4,12],"tags":[],"class_list":["entry","author-ikriv","post-751","post","type-post","status-publish","format-standard","category-hack","category-wpf"],"_links":{"self":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/751","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=751"}],"version-history":[{"count":0,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/751\/revisions"}],"wp:attachment":[{"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=751"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=751"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ikriv.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=751"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}