感覺也是很久沒有寫文章了,今天的問題仍然是與綁定有關,當然不再是簡單的集合數據綁定問題,這次還涉及到事件與RelayCommand綁定所相關的Converter,以及View層級上一些理解。
========================================================
上篇文章末尾的時候講了在List類中綁定ViewModel中的RelayCommand的時候應該用到RelativeSource來重定位DataContext從而跳出ItemsSource的方法,然而在接下來的開發中又遇到相似的問題。上代碼:
<TabControl TabStripPlacement="Top"
DataContext="{Binding Source={StaticResource Locator}, Path=LibraryControl}">
<TabItem Header="怪物庫">
<ListView ItemsSource="{Binding MonsterSection}" x:Name="monster_ListView">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseMove">
<command:EventToCommand Command="{Binding DataContext.MonsterMouseMove,
RelativeSource={RelativeSource AncestorType={x:Type TabControl},
Mode=FindAncestor, AncestorLevel=1}}"
EventArgsConverter="{StaticResource mscv}"
EventArgsConverterParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type TextBlock}, Mode=FindAncestor}}"
PassEventArgsToCommand="True"/>
</i:EventTrigger>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</TabItem>
</TabControl>
為了方便觀看我刪掉了其他多余的代碼,需要注意的是在Command的RelativeSource里面AncestorType是TabControl而不是他的任何一個TabItem,而其實這里只能是TabControl,雖然的確DataContext是具有繼承特征的(例如一個TabItem的DataContext為空則會往UI樹向上尋找可填充的DataContext),但是這里用TabItem卻沒辦法很好的繼承這個DataContext,那是因為DataTemplate,以及其他模板類的標簽,在UI樹的層面上都是和Item平行的,也就是:
<TabControl>
<Template>
<!--sth..-->
</Template>
<TabItem>
<!--sth..-->
</TabItem>
</TabControl>
TabItem并不是這個模板中內容的祖先,雖然繼承了同樣的DataContext,卻無法被尋找到,在有模板的情況下直接找具有有效Context的UI層級似乎才是最不容易出錯的方法。而在模板之中就不用顧慮這些,直接用FindAncestor的方法就可以找到,順帶一提就是RelativeSource在FindAncestor的時候是會自動忽略非目標類型的層級的(詳見深入淺出WPF的綁定一章)。
=======================================================
在MVVM模式下編寫程序時,常常會遇到事件與RelayCommand的各種復雜的轉換,其中就牽涉到事件的各個參數的傳遞與轉換,其中最為基本的路由事件的參數轉換器:
public class Converter : IEventArgsConverter
{
public object Convert(object value, object parameter) {
//need to return a value;
}
}
其中value是當前轉換的事件的EventArgs參數,另外一個則是在View中傳入的,Convert是必須實現的接口,實現之后就可以被外部引用并使用了。
其實這個地方的難點主要在于傳入的參數,考慮到后面程序的需要而正確的傳入參數很是考驗綁定知識的基本功..
順帶一提在這次開發中又發現一個wpf萬年老bug,那就是Mouse.GetPositon(Control)
這個函數無法返回正確的相對坐標值,需要利用當前的EventArgs來返回正確的坐標,例如args.GetPosition(Control)
,詳細請看StackOverflow,一搜就是。
歡迎指正。