WPF-WPF的内部世界-Binding
1.什么是Binding
数据绑定是在应用 UI 与其显示的数据之间建立连接的过程。数据绑定的典型用法是将服务器或本地配置数据放置到窗体或其他 UI 控件中。
2.为什么使用Binding
本质上支持数据绑定的大量属性、灵活的数据 UI 表示形式以及业务逻辑与 UI 的完全分离。
3.怎么使用Binding
3.1绑定的基本概念
不论要绑定什么元素,也不论数据源是什么性质,每个绑定都始终遵循下图所示的模型
通常情况下绑定需要这几个组件
- 目标
- 数据源
- 绑定
3.2 将控件作为源
<TextBox x:Name="textBox1" Text="{Binding Path=Value ,ElementName=slider1,UpdateSourceTrigger=PropertyChanged}" BorderBrush="Black" Margin="5" ></TextBox>
<Slider x:Name="slider1" Maximum="100" Minimum="0" Margin="5"/>
等价于
this.textBox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = "silder1" });
3.3 数据的流向
在默认的情况下数据既能通过binding送达目标,也能从目标返回源,
控制binding数据流向的属性是Mode,类型为BindingMode枚举,可取值为
- OneWay
- TwoWay
- OnTime
- OneWayToSource
- Default
这里的Default是根据实际情况去确定,若是可编辑的,Default就采用双向的,若是只读的就采用单向的。
3.4 数据的更新
控制binding数据更新的属性是,类型为UpdateSourceTrigger枚举,可取值为
- ProPertyChanged
- LostFocus
- Explicit
- Default
Binding还有NotifyOnSourceUpdated ,NotifyOnTargetUpdated两个bool属性,设置为true,当源或者目标被更新之后汇激发出相应的事件,在实际工作中我们可以通过监听这两个事件来找出有哪些数据和控件被更新了。
3.5 binding的路径
作为binding源的对象有很多属性,通过这些属性binding源可以把数据暴露给外界,而关注哪个属性值有binding的path指定
最简单的情况就是把binding关联在binding源的属性上
binding还支持多级路径,通俗的来说就是一路点下去
当使用一个集合或者dataview作为binding源时,如果我们想把它的默认元素当作path使用,如果集合中的属性还是一个集合,可以一路斜线下去
List<string> stringlist = new List<string>() { "tom", "luxi", "bob" };
this.textBox1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = stringList });
this.textBox1.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = stringList });
3.6 为binding指定源的几种方法
- 单个对象:包括.NET Fram自带类型对象和用户自定义的对象。如果类实现了INotifyPropertyChanged接口,则可通过属性中的set语句激发PropertyChanged事件来通知binding数据已被更新
- 集合类型:将集合作为ItemsControl派生类的数据源来使用,一般将控件的ItemsControl属性使用binding关联到集合对象上
- ADO.NET数据对象:DataTable DataView
- XML数据
- 依赖对象
- 容器的DataContext(WPF Data Binding的默认行为)
- 通过ElementName
- Binding的RelativeSource属性:当控件需要关注自己的容器或者内部元素的某个值
- ObjectDataProvider
- LINQ检索
3.7 Binding对数据的校验
Binding用于数据有效性校验的就是他的ValidationRules属性,其属性类型是Collection
1.继承ValidationRule抽象类,重写Validate方法
2.为binding添加此校验规则
3.默认是不对源进行数据的校验,设置ValidationRule的ValidatesOnTargetUpdated属性为true即可对元数据进行校验
public MainWindow()
{
InitializeComponent();
Binding binding = new Binding("Value") {Source = this.slider1 };
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
RangeValidationRule rvr = new RangeValidationRule();
rvr.ValidatesOnTargetUpdated = true;
binding.ValidationRules.Add(rvr);
// binding.NotifyOnValidationError = true;
this.textbox1.SetBinding(TextBox.TextProperty, binding);
// this.textbox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));
}
class RangeValidationRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
double d = 0;
if (double.TryParse(value.ToString(),out d))
{
if (d >= 0 && d <= 100)
{
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "valication false");
}
}
/**
void ValidationError(object sender,RoutedEventArgs args)
{
if (Validation.GetErrors(this.textbox1).Count > 0)
{
this.textbox1.ToolTip = Validation.GetErrors(this.textbox1)[0].ErrorContent.ToString();
}
}
**/
<StackPanel>
<TextBox x:Name="textbox1" Margin="5"></TextBox>
<Slider x:Name="slider1" Margin="5" Minimum="-10" Maximum="100"/>
</StackPanel>
3.8 Binding对数据的转化
默认转化的,可手动改写
3.9 MultliBinding(多路binding)
使一个目标绑定多个源
1.声明Mltlibinding类
2.在类中添加binding类
3.设置其路由
4.将目标和Mutlibinding关联
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.SetMultiBinding();
}
private void SetMultiBinding()
{
Binding binding01 = new Binding("Text") { Source = this.textbox1 };
Binding binding02 = new Binding("Text") { Source = this.textbox2 };
Binding binding03 = new Binding("Text") { Source = this.textbox3 };
Binding binding04 = new Binding("Text") { Source = this.textbox4 };
MultiBinding mb = new MultiBinding() { Mode = BindingMode.OneWay };
mb.Bindings.Add(binding01);
mb.Bindings.Add(binding02);
mb.Bindings.Add(binding03);
mb.Bindings.Add(binding04);
mb.Converter = new LoginMultiConvert();
this.button1.SetBinding(Button.IsEnabledProperty, mb);
}
}
public class LoginMultiConvert : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (!values.Cast<string>().Any(text => string.IsNullOrEmpty(text)) && values[0].ToString() == values[1].ToString() && values[2].ToString() == values[3].ToString())
{
return true;
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<StackPanel Background="LightBlue">
<TextBox Name="textbox1" Height="23" Margin="5"/>
<TextBox Name="textbox2" Height="23" Margin="5"/>
<TextBox Name="textbox3" Height="23" Margin="5"/>
<TextBox Name="textbox4" Height="23" Margin="5"/>
<Button x:Name="button1" Content="submit" Width="80" Margin="5"/>
</StackPanel>
随笔资料大量来自于《深入浅出WPF》 和官方文档