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