Tuesday, June 22, 2010

Wpf, Resources and DataContext

One of the frustrating things in WPF is that objects in the Resources Collection can't see the DataContext from their containing control. It makes sense when you think about it as they are not within the Logical / Visual Tree, which Dependency Properties can inherit down. Whilst it doesn't normally affect me, today I came across a need to have this.

I've just worked on a view where we want to expose a collection in a next-previous way, and expose a 'CurrentItem' property. Whilst we could have done it in our ViewModel, in our scenario we don't want the ViewModels becoming aware of the next / prev, and just to be aware that they are given a list of items, and one of them is selected.

I went down the approach of a control which inherited from FrameworkElement as it had a DataContext then put it in the Resources Collection. Of course this didn't work as as we said at the beginning, stuff in the Resources cannot access the DataContext. BUT back up a minute... there is a control which seems able to do this - the CollectionViewSource. How does it do it? Heh heh, Reflector revealed the internal hack which MS used to somehow ram the inheritence of DP's into this unsuspecting class.

Nasty, but it just so happens we can exploit this for our own purposes. CollectionViewSource wraps a collection which it can obtain by binding to the DataContext, and it is not marked as sealed so we can extend it and add our own behaviour.

What I ended up doing was subclassing CollectionViewSource and adding a NextCommand, PreviousCommand, and SelectedItem dependency property to my subclass. (side note - we use a OneWayToSource binding to reverse the SelectedItem back onto the ViewModel we can bind to a standard .Net property on the ViewModel).

All sounds good, but there was one more issue. The CollectionViewSource is a bit of a liar, in that when you bind to it, you don't actually bind directly to it, but instead to the Collection it exposes. It makes for a nicer syntax in that 99% of times you use it, all you are interested in is that exposed collection. For us though we need to drill into our actual class to get at our subclasses properties. That's where that strange property on Binding, BindsDirectlyToSource comes in. It lets us probe past that outer facade of the class and get into the real object.

Our code is not far off being acceptable now. It looks something like:

<SummaryContentActionView> <!-- the scaffolding view which uses a template to define the layout -->

<SummaryContentActionView.Resources>
<NextPreviousCollection x:Key="col" Items="{Binding Contract.Items}" SelectedItem="{Binding SelectedItem, Mode=OneWayToSource}" />
</SummaryContentActionView.Resources>

<SummaryContentActionView.MainContent> <!-- object DP exposed from the scaffold contol -->
<StackPanel>
<Button Command="{Binding Source={StaticResource col}, Path=NextCommand, BindsDirectlyToSource=True}" />
</StackPanel>
</SummaryContentActionView.MainContent>


</SummaryContentActionView>

22 comments:

Anonymous said...

很喜歡你的部落格 留言支持你 祝你人氣長紅~~~......................................................................

Anonymous said...

生存乃是不斷地在內心與靈魂交戰;寫作是坐著審判自己。......................................................................

祥傑祥傑 said...

在莫非定律中有項笨蛋定律:「一個組織中的笨蛋,恆大於等於三分之二。」.................................................................

Anonymous said...

成熟,就是有能力適應生活中的模糊。.................................................................

Anonymous said...

唯有學習不已的老師,才能認真的教,唯有燃燒自己,才能點亮他人的燈............................................................

Anonymous said...

字是活的,人和環境的觀察是活的,思想是活的。不管怎樣,就是要有一兩樣是活的。否則都是平庸。............................................................

Anonymous said...

開心不開心都是一天,祝您能夠笑著面對一切!............................................................

Anonymous said...

Never put off till tomorrow what may be done today.......................................................................

Anonymous said...

生存乃是不斷地在內心與靈魂交戰;寫作是坐著審判自己。..................................................

Anonymous said...

道歉是人類一定必要的禮節..................................................

Anonymous said...

幫你推個文~~期待更新!加油啊!............................................................

Anonymous said...

大肚能容,了卻人間多少事,滿腔歡喜,笑開天下古今愁。..................................................

Anonymous said...

好文!值得一推~~加油哦!............................................................

Anonymous said...

愛,拆開來是心和受兩個字。用心去接受對方的一切,用心去愛對方的所有。......................................................................

Anonymous said...

朋友是一面鏡子............................................................

Anonymous said...

財富並非永遠的朋友,但朋友卻是永遠的財富。......................................................................

Anonymous said...

嗯~蠻不錯耶~~我喜歡 ∩ 3∩............................................................

Anonymous said...

你的部落格感覺很棒,nice job!............................................................

Anonymous said...

好文章就值得回響,如果可以常常看到您的更新,應該是件很幸福的事情~~...............................................................

Anonymous said...

上班很累,摸個魚輕輕鬆鬆的逛部落

Anonymous said...

讓好心情回味發酵;壞心情留在文字裡隨時間消逝吧!............................................................

Anonymous said...

That is nice information. I love this types of post.
Thanks a lot..
fostering agencies London