WPF的绑定模式(mode)是枚举的 枚举值共有5个
1:OneWay(源变就更新目标属性)
2:TwoWay(源变就更新目标并且目标变就更新源)
3:OneTime(只根据源来设置目标,以后都不会变)
4:OneWayToSource(与OneWay相反)
5:Default(可以单向或双向,是靠被值定的源或目标是否有get或set来指定的)
所以绑定的话是需要选上面5个中的一个模式的,根据你的需要来选择,不选的话就会自动选择第五个的
Binding
作为数据传送UI的通道,通过INotityPropertyChanged
接口的PropertyChanged
事件通知Binding
数据属性发生改变
public class Product : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
if (PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
通过Binding关联UI控件元素
this.txtOfProduct.SetBinding(TextBox.TextProperty, new Binding() { Path = new PropertyPath("Name"), Source = p });
<TextBox x:Name="TextBox1" Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}">TextBox>
<Slider x:Name="slider1" Margin="5">Slider>
TextBox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = "slider1", Mode=BindingMode.OneWay });
<TextBox x:Name="TextBox1" Margin="5" TextWrapping="Wrap" >TextBox>
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text.Length}">TextBlock>
Path的索引器方式
<TextBox x:Name="TextBox1" Margin="5" TextWrapping="Wrap" >TextBox>
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text.[2]}">TextBlock>
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text[2]}">TextBlock>
当使用一个集合或者DataView
作为Binding
源时,如果我们想把它的默认元素作为Path来使用
List<string> names = new List<string>() { "张三", "李四", "王五" };
//张三
this.TextBox1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = names });
//“张三”字符串的长度
this.TextBox2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = names,Mode=BindingMode.OneWay});
//获取“张三”字符串中的第1个字符
this.TextBox3.SetBinding(TextBox.TextProperty, new Binding("/[0]") { Source = names, Mode = BindingMode.OneWay });
如果集合中嵌套集合,我们依然可以通过多级"/"语法把子集作为Path的元素
class City
{
public string Name { get; set; }
}
class Province
{
public List Citys { get; set; }
public string Name { get; set; }
}
class Country
{
public List Provinces { get; set; }
public string Name { get; set; }
}
TextBox1.SetBinding(TextBox.TextProperty, new Binding("/Name") { Source = countries });
TextBox2.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Name") { Source = countries });
TextBox3.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Citys/Name") { Source = countries });
sys
需要引用xmlns:sys="clr-namespace:System;assembly=mscorlib"
<StackPanel.Resources>
<sys:String x:Key="text">
WPF入门手册
sys:String>
StackPanel.Resources>
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding .,Source={StaticResource ResourceKey=text}}" >TextBox>
TextBox2.SetBinding(TextBox.TextProperty, new Binding(".") { Source = "WPF技术入门" });
没有Path和Source,Binding可以通过DataContext获取数据
<StackPanel.DataContext>
<sys:String>
WPF入门手册
sys:String>
StackPanel.DataContext>
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding Mode=OneWay}" >TextBox>
<TextBox x:Name="TextBox1" Margin="5" >TextBox>
<ListBox x:Name="ListBox1">ListBox>
List cities = new List() {
new City() { Id=1,Name="北京" },
new City() { Id=2,Name="昆明" },
new City() { Id=3,Name="上海" },
new City() { Id=4,Name="厦门" },
new City() { Id=5,Name="广州" }
};
this.ListBox1.ItemsSource = cities;
this.ListBox1.DisplayMemberPath = "Name";
this.TextBox1.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = this.ListBox1 });
当Binding
有明确的数据源的时,我们可以通过Soure
或ElementName
赋值办法关联Binding
,但有事我们不知道Soure
对象的名字是什么,却知道它与作为Binding
目标对象的UI元素布局上的相对关系,通过RelativeSourceMode
枚举设置关联的对象关系
<Grid x:Name="g1">
<StackPanel x:Name="s1">
<DockPanel x:Name="d1">
<TextBox x:Name="TextBox1" Margin="5" >TextBox>
DockPanel>
StackPanel>
Grid>
后台代码处理
RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor)
{
AncestorLevel = 1,
AncestorType = typeof(StackPanel)
};
//将StackPanel的Name s1赋给了TextBox1的Text
TextBox1.SetBinding(TextBox.TextProperty, new Binding("Name") { RelativeSource = rs });
也可以通过XAML的方式赋值
<Grid x:Name="g1">
<StackPanel x:Name="s1">
<DockPanel x:Name="d1">
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type DockPanel},AncestorLevel=1,Mode=FindAncestor}, Path=Name}" >TextBox>
DockPanel>
StackPanel>
Grid>
Binding
的ValidationRules
属性的类型为Collection
。通过实现Validate
方法返回给ValidationResult
对象,并设置IsVaild
属性,ErrorContent
属性可以接受一个字符串。
public class RangValidationRule : ValidationRule
{
//验证数据
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
double d = 0;
if (double.TryParse(value.ToString(), out d))
{
if (d >= 1 && d <= 100)
{
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "数据错误");
}
}
<TextBox x:Name="TextBox1" Margin="5">TextBox>
<Slider x:Name="slider1" Minimum="1" Maximum="100" Margin="5">Slider>
Binding binding = new Binding("Value") {
Source=slider1,
UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged,
};
binding.ValidationRules.Add(new RangValidationRule());
this.TextBox1.SetBinding(TextBox.TextProperty, binding);
public MainWindow()
{
InitializeComponent();
Binding binding = new Binding("Value")
{
Source = slider1,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
NotifyOnValidationError = true//开启错误通知
};
binding.ValidationRules.Add(new RangValidationRule());
this.TextBox1.SetBinding(TextBox.TextProperty, binding);
//注册验证错误事件
this.TextBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationErrorNotify));
}
private void ValidationErrorNotify(object sender, RoutedEventArgs e)
{
var errors = Validation.GetErrors(this.TextBox1);
if (errors.Count > 0)
{
TextBlock1.Text = errors[0].ErrorContent.ToString();
}
}
一般我们在做注册用户功能的时候,输入密码的时候都需要再确认输入密码,比较两次输入是否一致,现在我们可以通过多路Binding来简单的实现这个功能
首先实现一个IMultiValueConverter
接口功能,如果两次密码一致,提交按钮状态为可用
public class SubmitMultiBindingConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return (!values.Cast<string>().Any(a => string.IsNullOrEmpty(a))/*验证所有元素非空*/ &&
values[0].ToString() == values[1].ToString())/*值1=值2*/;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML代码
<TextBox x:Name="Password" Margin="5">TextBox>
<TextBox x:Name="Passworder" Margin="5">TextBox>
<Button x:Name="Submit" Content="提交" Margin="10" Height="30" Width="100">Button>
后台Binding
Binding pwdBinding = new Binding("Text") { Source = Password };
Binding pwderBinding = new Binding("Text") { Source = Passworder };
MultiBinding multi = new MultiBinding() { Mode=BindingMode.OneWay};
multi.Bindings.Add(pwdBinding);
multi.Bindings.Add(pwderBinding);
multi.Converter = new SubmitMultiBindingConverter();
Submit.SetBinding(Button.IsEnabledProperty, multi);