Binding概念理解:
WPF为了实现了UI与数据逻辑的解耦,将UI从数据逻辑中分离出来形成Xaml文件,而UI与数据逻辑之间的联系则通过Bingding来实现。Bingding就像UI与数据逻辑之间的桥梁,能够让分离的两部分组合成一个整体,实现WPF的数据驱动。
把Binding比作桥梁,那么它的两端分别是Binding的源(Source)和目标(Target),Path为Binding指定访问路径,数据从哪里来哪里就是源(未指明Source,数据就会一直往上查找),Bingding是驾在中间的桥梁,Bingding的目标是数据去向哪里。当Bingding的源变化需要通知目标变化时,需要通过属性的set语句激发一个ProtertyChanged事件。这个事件不需要我们自己声明,而是让数据源类实现System.ComponentModel名称空间中的INotifyPropertyChanged接口。
Binding数据流向的属性是Mode:TwoWay(双向)、OneWay(单向)、OneTime(单次)、OneWayToSource(对数据源单向)和Default(根据具体目标情况确定,如可编辑未双向模式)。数据源根据什么类型变化进行通知,可设置属性UpdateSourceTrigger:PropertyChanged、LostFocus、Explicit(显式,在程序启动时更新源)和Default。
实例链接:WPF Binding(绑定)详解实例
WPF前端数据绑定:
实例如下:拖动Slider滑块值时,绑定Slider.Value的TextBox.Text跟着变化。
WPF后端数据绑定:
实例如下:一个TextBox.Text绑定到另一个TextBox.Text,另一个TextBox.Text变化时它也跟着变化。
//1.创建Bingding
Binding binding = new Binding()
{
Source = tbSource, // 数据源
Path = new PropertyPath("Text"), // 需绑定的数据源属性名
Mode = BindingMode.TwoWay, // 绑定模式
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged //触发器
};
//2.设置Bingding
//方法1
//tbPath.SetBinding(TextBox.TextProperty, binding);
//方法2
BindingOperations.SetBinding(
tbPath // 需绑定的控件
,
TextBox.TextProperty // 需绑定的控件属性
,
binding);
Binding不同使用方式和场景:
Binding还支持多级路径。如,我们想让一个TextBox显示另一个TextBox的长度,可以这样写:
集合类型的索引器(Indexer)又称为带参数属性,所有索引器也能作为Path来使用。
当数据源本身就是数据就不需要使用Path指明,Path后面可以.来表示,也可以之间省略Path。
Hello World!
当数据源是集合时,可以通过"/"来表示。当结合元素的属性仍然时集合时,我们想不子级集合中的元素当作Path,则可以使用多级斜线的语法(如:"/Provinces/CityList.Name")。
当没有指定数据源时,Binding会沿着UI元素树一路向上找,每到一个结点就要看看这个结点的DataContext是否具有Path所指定的属性。如果有,那就把这个对象作为自己的Source。
//后台定义类
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
使用XML数据作为Binding源:
.Net Framework提供了两套处理XML数据的类库:符合DOM标准类库,以LINQ为基础的类库。大多数据传输基于SOAP(简单对象访问协议),而SOAP又是通过将对象序列化为XML文本进行传输。XML文本是树形结构,它能方便地用于线性结合和树形结构数据。使用XPath指明Binding XML路径,路径后使用@符号加字符串表示的是XML元素的Attribute,不加@的字符串表示的是子级元素。
DOM标准的XML类库:
LINQ查询的结果是IEnumerable
XDocument xdoc = XDocument.Load(@"E:\Xml\colors.xml");
listBox2.ItemsSource = from element in xdoc.Descendants("color") where element.Attribute("name").Value.StartsWith("b")
select new
{
Name=element.Attribute("name").Value,
ID= element.Attribute("ID").Value
};
listBox2.DisplayMemberPath = "Name";
使用ObectDataProvider对象作为Binding的Source:
在我们开发过程中,很难保证一个类所有数据都使用属性暴露出来,这个时候需要使用ObjectDataProvider来包装作为Binding源的数据对象。
实例:通过ObjectDataProvider传递对类方法并作为数据源。
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public Student GetStudent()
{
return new Student
{
Id = 2,
Name = "Jack",
Age = 9
};
}
}
使用Binding的RelativeSource属性进行绑定:
当我们不确定作为Source的对象叫什么名字,但知道它与作为Binding目标的对象在UI布局上有相对关系,比如控件自己关联自己的某个数据、关联自己某级容器的数据。这个时候我们就要使用Binding的RelativeSource属性。
实例:TextBox.Text绑定它上面布局元素的Name。
Binding对数据的转换和校验:
我们可以在连接Source和Target之间Binding桥上设置关卡,来判断哪些符号条件的数据流通。通过实现ValidationRule这个抽象类,对数进行校验。
实例:TextBox.Text与Slider.Value数值进行绑定,并对输入TextBox值进行校验,校验不通过则提示。
public 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, "Validation Failed");
}
}
public partial class ValidationRuleDemo : Window
{
public ValidationRuleDemo()
{
InitializeComponent();
Binding binding = new Binding("Value") { Source = this.slider1 };
binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
RangeValidationRule rule = new RangeValidationRule();
binding.ValidationRules.Add(rule);
//当数据校验失败时Binding会发出一个信号并以Binding对象的Target为起点在UI元素树上传播。
binding.NotifyOnValidationError = true;
this.textBox1.SetBinding(TextBox.TextProperty, binding);
this.textBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));
}
private void ValidationError(object sender, RoutedEventArgs e)
{
this.textBox1.ToolTip = Validation.GetErrors(this.textBox1)[0].ErrorContent.ToString();
}
}
Binding的数据转换(Converter):
我们在进行数据绑定时,Source和Target传递数据类型可能不一致,这个时候我们就可以用Converter进行数据转换。
实例:TextBox前景色绑定到自身输入的Text,并通过Converter进行类型转换。
public class BrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string color = System.Convert.ToString(value).ToLower();
switch(color)
{
case "red":
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(color));
case "green":
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(color));
case "blue":
return new SolidColorBrush((Color)ColorConverter.ConvertFromString(color));
}
return new SolidColorBrush(Colors.Black);
}
//双向转换回调
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var solidColorBrush = (SolidColorBrush)value;
if(solidColorBrush!=null)
{
return "Red";
}
return "Black";
}
}
多路绑定(MultiBinding):
实例:当多个TextBox输入字符一致时,Button的IsEnable属性为true,否Button不能点击。
public partial class MultiBindingDemo : Window
{
public MultiBindingDemo()
{
InitializeComponent();
SetMultiBinding();
}
private void SetMultiBinding()
{
Binding b1 = new Binding("Text") { Source = this.txt1 };
Binding b2 = new Binding("Text") { Source = this.txt2 };
Binding b3 = new Binding("Text") { Source = this.txt3 };
MultiBinding mb = new MultiBinding() { Mode = BindingMode.OneWay };
mb.Bindings.Add(b1);
mb.Bindings.Add(b2);
mb.Bindings.Add(b3);
mb.Converter = new MultiBindingConverter();
this.btn1.SetBinding(Button.IsEnabledProperty, mb);
}
}
public class MultiBindingConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if(!values.Cast().Any(text=>string.IsNullOrEmpty(text))&&values[0].ToString()==values[1].ToString() && values[0].ToString() == values[2].ToString())
{
return true;
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
实例链接:WPF Binding(绑定)详解实例