xaml中DataTemplate的內容綁定ItemSource以外的對象
問題描述
一般來說在DataTemplate中每個Item所顯示的內容都是跟它所綁定ItemSource相關的,但是有時候我們可能需要在每個Item上綁定顯示一些ItemSource中沒有的東西,比如說在一些監控程序中,可能需要用一個ListBox顯示多個監控數據和一些監控數據中沒有的東西,比如軟件版本號什麼的。
xaml中的綁定途徑
xaml中的Binding有3種途徑綁定數據:ElementName屬性,Source屬性,RelativeSource屬性。這裏簡單的說明一下。
- ElementName屬性
用來綁定界面上有設置過x:Name屬性的元素屬性。
<StackPanel>
<Label x:Name="lb_Test" Content="Test"/>
<Button Content="{Binding ElementName=lb_Test,Path=Content}"/>
</StackPanel>
- Source屬性
用於綁定確定的對象,如資源字典中的靜態資源
<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=PersonName}"/>
- RelativeSource屬性
用於綁定不確定的對象,如在DataTemplate中綁定ItemSource以外的對象。這裏這個就是我們需要用到的。
實現代碼
該代碼實現在一個ListBox中爲每個Item綁定ItemSource以外的對象。
按照MVVM的模式,先看ItemSource中綁定的數據和ViewModel,ViewModel作爲整個View的數據源。
ListBox中每個Item綁定的數據,包含一個int和一個string
public class DataModel : INotifyPropertyChanged
{
private int m_Num;
public int Num
{
get
{
return m_Num;
}
set
{
m_Num = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Content"));
}
}
private string m_Content;
public string Content
{
get
{
return m_Content;
}
set
{
m_Content = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Content"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
ViewModel作爲整個頁面的DataContext,它包含一個數組(供ListBox綁定)和一個版本字符串。
public class ViewModel
{
public ObservableCollection<DataModel> ModelList { get; set; }
public string VersionText { get; set; }
public ViewModel(List<DataModel> data)
{
ModelList = new ObservableCollection<DataModel>(data);
VersionText = "Ver 1.01";
}
}
頁面中的ListBox以ViewModel中的ModelList作爲ItemSource,建立DataTemplate
<ListBox ItemsSource="{Binding Path=ModelList,Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<!--綁定ItemSource中一個Item的Num屬性-->
<TextBlock Text="{Binding Content}"/>
<!--綁定ItemSource中一個Item的Num屬性-->
<TextBlock Text="{Binding Num}"/>
<!--綁定ItemSource以外的一個字符串-->
<TextBlock Text="{Binding DataContext.VersionText, RelativeSource={RelativeSource AncestorType=local:MainWindow}}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
成功綁定
這裏的XAML最核心的代碼是這一行
<TextBlock Text="{Binding DataContext.VersionText, RelativeSource={RelativeSource AncestorType=local:MainWindow}}"/>
當xaml渲染到這個TextBlock的時候,它綁定的DataContext已經是ModelList中的其中一個DataModel對象,所以它默認只能訪問到DataModel對象中的Num和Content屬性。這行代碼的功能是將這個TextBlock綁定的DataContext切換爲ViewModel裏面的VersionText屬性,此時這個TextBlock必須綁定中父鏈中的祖先,綁定父級(ModelList)的父級(ViewModel)元素.
RelativeSource={RelativeSource AncestorType=local:MainWindow}
這句的意思是,表明該綁定值需要向上查找父級鏈,直到查找到一個類型爲MainWindow的對象爲止,然後綁定它的DataContext.VersionText屬性。
參考
1.xaml中三種綁定模式的綁定方法
2.xaml中Binding的用法
3.How to: Specify the Binding Source