绑定对象:
数据绑定关键是System.Windows.Data.Binding对象,会将2个属性粘在一起,并在它们间建立通信信道。
1.代码实现绑定
//创建一绑定对象
Binding binding = new Binding();
//设置数据源对象(此处数据源来至textBox1)
binding.Source = textBox1;
//设置数据源对象的哪一个属性提供数据
binding.Path = new PropertyPath("Text");
//将textBlock1的依赖属性Text和绑定对象关联
textBlock1.SetBinding(TextBlock.TextProperty, binding);
//绑定的另一种方法,第一个参数为DependencyObject对象
//支持不是从FrameworkElement或FrameworkContentElement继承而来的对象数据绑定
//BindingOperations.SetBinding(textBlock1, TextBlock.TextProperty, binding);
//移除绑定
//BindingOperations.ClearBinding(textBlock1, TextBlock.TextProperty);
2.XAML中实现绑定
<TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0"
Name="textBox1" VerticalAlignment="Top" Width="120" />
<!-- 此处Binding用无参构函构造,后在设置其2个属性值 -->
<TextBlock Height="23" HorizontalAlignment="Left" Margin="12,41,0,0"
Name="textBlock1" VerticalAlignment="Top"
Text="{Binding ElementName=textBox1, Path=Text}" />
<!-- 另一绑定方式:此处Binding用含一个参数构函构造,后在设置其1个属性值 -->
<TextBlock Height="23" HorizontalAlignment="Left" Margin="12,41,0,0"
Name="textBlock1" VerticalAlignment="Top"
Text="{Binding Text, ElementName=textBox1}" />
注意:XAML使用Binding的ElementName属性设置源对象,其实这2个属性都有效,只是在XAML中使用ElementName更方便,只需给源元素名就可以了。
在XAML中设置Source,目标对象必须被定义在某Resources资源中。
<Page.Resources>
<TextBox x:Key="textBox1" Text="lulu"></TextBox>
</Page.Resources>
<StackPanel>
<!-- Binding使用Source指定目标元素 -->
<TextBlock Height="23" HorizontalAlignment="Left" Margin="12,41,0,0"
Name="textBlock1" VerticalAlignment="Top"
Text="{Binding Text, Source={StaticResource textBox1}}" />
</StackPanel>
与普通.NET属性绑定:
<Page.Resources>
<!-- 定义一个集合 -->
<ResourceDictionary x:Key="dictionary">
<Color x:Key="1" A="255" R="255" G="255" B="255"/>
<Color x:Key="2" A="255" R="255" G="0" B="0"/>
</ResourceDictionary>
</Page.Resources>
<!-- Label值显示2,因为集合不是FrameworkElement也不是FrameworkContentElement,因此放在逻辑资源里通过StaticResource访问 -->
<Label Content="{Binding Count, Source={StaticResource dictionary}}" />
注:使用普通.NET属性为数据源绑定,因为没有依赖属性的自动变更机制,源属性值改变,目标属性不会变化。
绑定整个对象:
源属性(即Binding的Path属性)是可选的!省略该属性将制动绑定整个对象。
<!-- Label值显示:(集合) -->
<Label Content="{Binding Source={StaticResource dictionary}}" />
绑定到集合:
class PhotoModel
{
private string _path;
private string _name;
private Image _image;
public string Path
{
get { return _path; }
set { _path = value; }
}
public string Name
{
get { return _name; }
set { _name = value; }
}
//构造函数
public PhotoModel(string path, string name)
{
_path = path;
_name = name;
}
//重写ToString(),可不指定元素DisplayMemberPath属性,显示需要显示的属性值
public override string ToString()
{
return _path;
}
}
//PhotoList继承ObservableCollection使得非依赖属性可实现自动跟新绑定值
class PhotoList : System.Collections.ObjectModel.ObservableCollection<PhotoModel>
{ }
/// <summary>
/// BindPage.xaml 的交互逻辑
/// </summary>
public partial class BindPage : Page
{
PhotoList pl;
public BindPage()
{
//创建数据源
pl = new PhotoList();
pl.Add(new PhotoModel("img/a.jpg", "a.jpg"));
pl.Add(new PhotoModel("img/b.jpg", "b.jpg"));
pl.Add(new PhotoModel("img/c.jpg", "c.jpg"));
//将数据源添加到当前页的逻辑资源中
Resources.Add("photoList", pl);
InitializeComponent();
}
#region Event
private void Button_Click(object sender, RoutedEventArgs e)
{
//修改数据源
pl.RemoveAt(pl.Count-1);
}
#endregion
}
<Page.Resources>
<SolidColorBrush x:Key="red" Color="red" />
<!-- 定义字典集合 -->
<ResourceDictionary x:Key="dic" />
</Page.Resources>
<StackPanel>
<Label Content="{Binding Count, Source={StaticResource dic}}" />
<!-- 配置DisplayMemberPath要显示的PhotoModel元素中Name属性值 -->
<!-- 配置IsSynchronizedWithCurrentItem可同步选中同一数据源Selector控件选择项 -->
<ListBox x:Name="listBox1" DisplayMemberPath="Name" ItemsSource="{Binding Source={StaticResource photoList}}"
IsSynchronizedWithCurrentItem="True"/>
<ListBox x:Name="listBox2" DisplayMemberPath="Path" ItemsSource="{Binding Source={StaticResource photoList}}"
IsSynchronizedWithCurrentItem="True"/>
<Button Height="33" Width="83" Content="修改数据源" Click="Button_Click" />
</StackPanel>
DataContext共享源:
对于同一页面不同控件,绑定到同一源对象上,WPF可指定一隐式数据源,而不用显示调用Binding标记每个Source,RelativeSource,ElementName。这种隐式数据源也叫数据上下文(DataContext)。设置父元素的DataContext属性为这个源对象。
<StackPanel Name="parent" DataContext="{StaticResource photoList}">
<!-- 配置DisplayMemberPath要显示的PhotoModel元素中Name属性值 -->
<!-- 配置SelectedValuePath选中的Value值属性 -->
<!-- 配置IsSynchronizedWithCurrentItem可同步选中同一数据源Selector控件选择项 -->
<ListBox x:Name="listBox1" SelectedValuePath="Name" DisplayMemberPath="Name" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"/>
<ListBox x:Name="listBox2" DisplayMemberPath="Path" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"/>
<Button Height="33" Width="83" Content="修改数据源" Click="Button_Click" />
</StackPanel>
用代码实现DataContext
InitializeComponent();
//在InitializeComponent()后调用,否者parent元素对象还未构建成功,会报错
//用此种方法可以避免将数据源对象保存为一资源
parent.DataContext = pl;
控制呈现:
1.使用数据模板
数据模板是一种用户界面。
<StackPanel Name="parent">
<ListBox x:Name="listBox1" SelectedValuePath="Name" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True" SelectionChanged="listBox2_SelectionChanged">
<ListBox.ItemTemplate>
<!-- 数据模板,用于显示一个图片 -->
<!-- DataTemplate通常被当做一资源,可为多个元素共享,无论属性元素在哪里 -->
<DataTemplate DataType="Button">
<!-- 注:此Path非彼Path,是指PhotoModel对象中Path属性 -->
<Image Source="{Binding Path}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- button显示:img/a.jpg -->
<Button Name="button1" Height="33" Width="83" Content="{Binding Path}" Click="Button_Click" />
</StackPanel>
2.使用值转换器
namespace WPF_Test
{
//绑定值笔刷转换器
class CountToBackgroundConverter : IValueConverter
{
#region IValueConverter 成员
//源实例转换为目标实例
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//检查当前转换目标是否为Brush对象
if(targetType != typeof(Brush))
{
throw new InvalidOperationException("转换目标必须为Brush!");
}
int id = int.Parse(value.ToString());
switch(id)
{
case 1:
return Brushes.YellowGreen;
case 2:
return Brushes.Orange;
case 3:
return Brushes.SkyBlue;
default:
//返回用户定义的参数
return parameter;
}
}
//目标实例转换为源实例
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
#endregion
}
//格式化绑定值转换器
class FormatConverter : IValueConverter
{
#region IValueConverter 成员
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int num = int.Parse(value.ToString());
return num + (num <= 1 ? "Item" : "Items");
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
}
<!-- 在当前Page中引用自定义命名空间 -->
xmlns:custom="clr-namespace:WPF_Test"
<Page.Resources>
<!-- 定义自定义类 -->
<custom:CountToBackgroundConverter x:Key="myConverter"/>
<custom:FormatConverter x:Key="myFormatConverter"/>
</Page.Resources>
<StackPanel Name="parent">
<ListBox x:Name="listBox1" SelectedValuePath="Name" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate DataType="Button">
<StackPanel>
<!-- 使用Binding的Converter属性插入自定义值转换器,将绑定数据ID值转换为需要的Brushes类型 -->
<Label Background="{Binding ID, ConverterParameter=Red,
Converter={StaticResource myConverter}}" Content="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<!-- 每次源值改变,Convert方法都会调用 -->
<Label Content="{Binding Count, Converter={StaticResource myFormatConverter}}" />
<!-- button显示:img/a.jpg -->
<Button Name="button1" Height="33" Width="83" Content="{Binding Path}" Click="Button_Click" />
</StackPanel>