WPF9 Binding-1
2021-03-02 03:28
标签:table student 实现 TreeView initial 列表 控制 外衣 lin 程序的本质是数据加算法。数据会在存储、逻辑和展示三个层流通,在数据角度上看,三层都很重要,但从算法角度上来看,算法在程序中的分布就不是很均匀,对于一个三层结构的程序来说,算法一般分布在: A、数据库内部 B、读取和写会数据 C、业务逻辑 D、数据展示 E、界面和逻辑的交互 A、B两个部分的算法一般都非常稳定,不会轻易改动,复用性也很高;C处与客户需求关系最紧密,最复杂,变动也最大,大多数算法都集中在此;D、E两层负责UI与逻辑的交互,也占有一定量的算法。 C是程序的核心,是占用开发精力最多的地方,但D、E却因为与逻辑层紧密相关,而容易把本应该写在逻辑层里的算法写在D、E部分(所以才有了MVC等模式)。WPF可以让展示出永远处于逻辑层的从属地位,这种能力的实现关键是它引入了Data Binding概念以及配套的Dependency Property系统和DataTemplate。 Data Binding在WPF系统中起到的是数据告诉公路的作用,加工好的数据会自动送达用户界面加以显示,被用户修改过的数据也会自动传回逻辑层,一旦数据被加工好又会送达用户界面,这就是数据驱动UI,也是现在前端流行的各类MVVM框架的核心概念。 Binding的两端分别是源Source和目标Target,数据源是一个对象,这个对象可能有和很多数据,这些数据通过属性暴露给外界,UI上的元素关心的是哪个属性值的变化,这个属性就成为Binding的路径,但Binding还需要有一个自动机制,即当值变化后属性要有能力通知Binding,让Binding把变化传递给UI元素,这个功能的实现是在属性的set语句中激发一个PropertyChanged事件。这个事件不需要手动声明,要做的是让作为数据源的类实现System.ComponentModel名称空间中的INotifyPropertyChanged接口。当为Binding设置了数据源后,Binding就会自动监听来自这个接口的PropertyChanged事件。 为了在Student的值发生改变时有能力通知Binding,让Binding把变化传递给UI元素。方法是在属性的set语句中激发一个PropertyChanged事件。这个事件不需要自行声明,而是让作为数据源的类实现System.ComponentModel名称空间中的INotifyPropertyChanged接口。 在窗体上准备一个TextBox和一个Button,TextBox将作为Binding目标,Button的Click事件发生时会改变Student对象的Name属性值。 然后使用Binding把数据源和UI元素连接起来。 Student stu;声明在构造函数和按钮事件外是为了让Window的构造器和按钮事件都能访问由它引用的Student实例。 Binding部分,先创建Binding的实例,然后使用binding.Source=stu;为Binding实例指定数据源,最后使用binding.Path=new PropertyPath("Name");来为Binding指定访问路径。 把数据源和目标连接在一起的任务是使用"BindingOperations.SetBinding(...)"方法完成的,这个方法有三个重要参数: 1、第一个参数用于指定Binding的目标,本例中是this.textBox.Name 2、第二个参数用于为Binding指明把数据送达目标的哪个属性。但这个参数并没有使用对象的属性,而只是一个静态只读的DependencyProperty类型成员变量,这就是依赖属性。这类属性的值可以通过Binding依赖在其他对象的属性值上,被其他对象的属性值所驱动。 3、第三个参数很明了,就是指定使用哪个Binding实例将数据源与目标关联起来。 按钮事件用于对Name属性进行更新。 一、Binding的源和路径 Bingding的源也就是数据的源头。Binding对源的要求并不苛刻,只要它是一个对象,并且通过属性公开自己的数据,就能作为Binding的源。 数据源不仅仅可以是类(比如实现INotifyPropertyChanged接口,并在属性set语句中激发PropertyChanged事件),还可以是控件自己、自己的容器、子元素,另一个控件、集合(作为ItemsControl)的数据源、XML(TreeView、Menu的数据源)、把多个控件关联到一个“数据制高点”上,甚至不给Binding指定数据源,让他自己去寻找。 1、把控件作为Binding源和Binding标记扩展 大多数情况下Binding的源是逻辑层的对象,但有时候为了让UI元素产生一些联动效果,也会使用Binding在控件间关联。 WPF中,代码可以访问XAML代码中声明的变量,但XAML代码却无法访问C#代码中声明的变量、 上一句话等价于this.TextBox1.SetBinding(TextBox.TextProperty,new Binding("Value")){ElementName="slider"} 2、控制Binding的方向和数据更新 Binding在源和目标之间架起了沟通的桥梁,默认情况下数据既能够通过Binding送达目标,也能够从目标返回源(手机用户对数据的修改)。有时候数据只需要展示给用户、不允许用户修改,这时候可以把Binding模式更改为源向目标的单项沟通。 控制Binding数据流向的属性是Mode,它的类型是BindingMode枚举。BindingMode可取值为TwoWay、OneWay、OnTime、OneWayToSource和Default。这里的Default值是指Binding的模式会根据目标的实际情况来确定,比如若是可编辑的(TextBox.Text属性),Default就采用双向模式;若是只读的(TextBlock.Text)就采用单向模式。 Binding的另一个属性——UpdateSourceTrigger,它的类型是UpdateSourceTrigger枚举,可取值为PropertyChanged、LostFocus、Explicit、Default、 3、Binding的路径 作为Binding源的对象可以由很多属性,通过这些属性Binding源可以把数据暴露给外界。Binding Path属性来指定Binding到底关注那个属性的值。例如把Slider控件对象作为源、把它的Value属性作为路径。 等价于C#: Binding binding=new Binding(){Path=new PropertyPath("Value"),Source=this.slider}; this.textBox1.SetBinding(TextBox.TextProperty,binding); 也可以让一个TextBox显示另一个TextBox的文本长度 索引器也能作为Path来使用,比如让一个TextBox显示另一个TextBox文本的第四个字符 Text.[3]中的.可以去掉。 当使用一个集合或者DataView作为Binding源时,如果我们想把它的默认元素当做Path使用,则需要这样的语法: 如果要是用默认元素,则直接/即可,如果要取第3个元素/[2],如果要取子集合元素,则可以一路/下去。 4、没有path的Binding 当Binding源本身就是数据且不需要Path类指定时,Path就是一个.或者干脆没有Path的Binding。典型的,string、int等基本类型就是这样,它们的实例本身就是数据,则无法通过它的某个属性来访问这个数据,此时只需要把Path的值设置为.即可。XAML中可以省略,而C#中不可以。 等价于C#代码: Text="{Binding Source={StaticResource ResourceKey=myString}}" 4、为Binding指定源的集中方法 Binding的源时数据的来源,所以只要一个对象包含数据并能通过属性把数据暴露出来,它就能高档做Binding的源来使用,包含数据的对象比比皆是,但必须为Binding的Source指定合适的对象Binding才能正确工作。 常见的绑定方法有: A、把普通CLR类型单个对象指定为Source:包括.Net Framework自带类型对象和用户自定义类型的对象。如果类型实现了INotifyPropertyChanged接口,则可通过在属性的set语句里激发PropertyChanged事件来通知Binding数据已被更新。 B、把普通CLR集合类型对象指定为Source:包括数组、List C、把ADO.NET数据对象指定为Source,包括DataTable和DataView等对象。 D、使用XmlDataProvider把XML数据指定为Source:XML作为标准的数据存储和传输格式几乎无处不在,可以用它标识单个数据对象或集合; E、把依赖对象(Dependency Object)指定为Source:依赖对象不仅可以作为Binding的目标,同时也可以作为Binding的源。这样就有可能形成Binding链。依赖对象中的依赖属性可以作为Binding的Path。 F、把容器的DataContext指定为Source:(WPF Data Binding默认行为),直到从哪个属性获取数据,但把哪个对象作为Binding源还不能确定。此时,就可以先建立一个Binding、只给它设置Path而不设置Source,让这个Binding自己去寻找Source。此时,Binding会自动把控件的DataContext当做自己的Source(会沿着控件树一层一层向外找,直到找到带有Path指定属性的对象为止)。 G、通过ElementName指定Source:在C#代码里可以直接把对象作为Source赋值给Binding,但XAML无法访问对象,所以只能使用对象的Name属性来找到对象。 H、通过Binding的RelativeSource属性相对地指定Source,当控件需要关注自己的、自己容器的或自己内部元素的某个值就需要使用这种方法。 I、通过Binding的RelativeSource属性相对地指定Source,当控件需要关注自己的、自己容器的或者自己内部元素的某个值就需要使用这种方法。 J、把ObjectDataProvider对象指定为Source:当数据源的数据不是通过属性而是通过方法暴露给外界的时候,可以使用这两种对象来包装数据源并再把他们指定为Source。 5、没有Source的Binding-使用DataContext作为Binding的源 Binding可以把单个CLR类型对象指定为Binding的Source,但如果一个Binding只知道自己的Path而不知道自己的Source时,就会沿着UI元素树一路向树根找过去,没过一个节点就会看这个节点的DataContext是否具有Path所制定的属性。如果有,这把这个对象作为自己的Source,否则继续寻找。 此时属性结构就有一个DataContext:Student。 使用xmlns:local="clr-namespace:WPF_XMAL_6_Binding"就可以使用在C#中定义的Student类。 3个TextBox虽然没有指定Source,但Binding就会自动向UI树的长层去寻找可用的DataContext对象。Binding的Path可以设置为.,也可以直接省略不写。 Binding这么智能是因为,当没有为空间的某个依赖属性显式赋值时,空间会把自己容器的属性值借过来当自己的属性值,例如如果为一个Button所在的Grid设置DataContext=“6”,然后Button的事件中设置MessageBox.Show(btn.DataContext.ToString());,虽然Button本身没有值,但它会显式Grid的DataContext。 属性值沿着UI树向下传递了。 实际工作中DataContext用法非常灵活,比如: 1、当UI上的多个控件都使用Binding关注同一个对象时,不妨使用DataContext 2、当作为Source的对象不能被直接访问的时候,例如A窗体内的控件是private访问级别,B要去访问A窗体内的控件作为自己的Binding源,就可以把A窗体内的这个控件或控件的值作为窗体A的DataContext(这个属性是public级别)从而暴露数据。 6、使用集合对象作为列表控件的ItemSource WPF中的列表式控件都派生自ItemsControl类,也就自然继承了ItemsControl这个属性。ItemsSource属性可以接受一个IEnumerable接口派生类的实例作为自己的值,每个ItemsControl派生类都具有自己对应的条目容器,比如ListBox的条目容器是ListBoxItem,ItemSource里存放的是一条一条的数据,要想把数据显示出来需要为其穿上外衣,就是Binding。只要为每一个ItemsControl对象设置ItemsSource属性值,ItemsControl对象就会自动迭代其中的数据元素,为每个元素准备一个条目容器,并建立起关联。 7、使用Linq作为Binding的源 绑定到listViewStudents.ItemsSource上即可。 WPF9 Binding-1 标签:table student 实现 TreeView initial 列表 控制 外衣 lin 原文地址:https://www.cnblogs.com/NicolasLiaoran/p/13042975.html public class Student:INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
//触发事件
if(this.PropertyChanged!=null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
public partial class MainWindow : Window
{
Student stu;
public MainWindow()
{
InitializeComponent();
//准备数据源
stu = new Student();
//准备Binding
Binding binding = new Binding();
binding.Source = stu;
binding.Path = new PropertyPath("Name");
//使用Binding连接数据源与Binding目标
BindingOperations.SetBinding(this.textBoxName, TextBox.TextProperty, binding);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
stu.Name += "Name";
}
}
Liststring> stringList = new Liststring>() { "Tim", "Tom", "Blog" };
this.textbox4.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = stringList, Mode = BindingMode.OneWay });
public MainWindow()
{
InitializeComponent();
//准备数据
List
private void Button_Click_1(object sender, RoutedEventArgs e)
{
//获取DataTable实例
List