zoukankan      html  css  js  c++  java
  • WPF之Binding

    wpf致力于将业务逻辑层处于核心地位,展示层永远处于逻辑层的从属位置
    wpf的这种能力源于
    DataBinding 、与之配套的Dependency Property系统和DataTemplate
    
    Target  <=>  Binding  <=>  Source
    
    Binding的源:也就是数据的源头,只要求是个对象并通过属性公开自己的数据,它就能作为Binding源
    例如:
    1.把控件自己或者自己的容器或子级元素作为源
    2.用一个控件作为另一个控件的源
    3.把集合作为ItemsControl的数据源
    4.使用XML作为TreeView或Menu的数据源
    5.把多个控件关联到一个“数据制高点”上,甚至不给Binding指定数据源让它自己去找。
    
    控制Binding的方向和数据的更新
    
    控制Binding数据流向的属性是Model,它的类型是BindingModel
    BindingModel枚举
    TwoWay
    OneWay
    OnTime
    OneWayToSource
    Default 根据实际情况来定,可编辑的双向,只读的单向
    
    Binding数据更新的属性是
    UpdateSourceTrigger枚举
    PropertyChanged
    LostFocus
    Explicit
    Default
    另Binding还有一个属性NotifyOnSourceUpdated、NotifyOnTargetUpdated两个bool属性
    如果设为true,当源或目标更新时会激发相应的SourceUpdated事件和TargetUpdated事件
    
    
    Binding的路径Path
    来关注源中哪个属性的值,由path来指定,可以在Binding的构造器来指定,Path的实际类型是PropertyPath
    我们知道用一个控件可以作为另一个控件的源
    Path可以用来关注属性,而属性又分为无参属性、有参属性(索引器)
    针对于有参属性
    例如:textBox2显示textBox1的第四个文本字符。
    <TextBox x:Name="textBox1" BorderBrush="Black"  Margin="5" />
    <TextBox x:Name="textBox2" Text="{Binding Path=Text[3],ElementName=textBox1,Mode=OneWay}" Margin="5" BorderBrush="Black"/>
    
    当一个集合或DataView作为源时,如果想默认的元素当做Path使用,需要这样的语法
    List<string> list=new List<string>(){"Tom","Tim","Blog"};
    this.textBox1.SetBinding(TextBox.TextProperty,new Binding("/"){ Source=list});            //Tom
    this.textBox2.SetBinding(TextBox.TextProperty,new Binding("/Length"){ Source=list});    //3
    this.textBox3.SetBinding(TextBox.TextProperty,new Binding("/[2]"){ Source=list});        //m
    如果想把子集合中的元素当做Path,可以使用多级斜线的语法
    
    没有Path的Binding
    实例本身就是数据源,不需要Path来指明,例如string int等基本类型就是,实例本身就是数据,无法通过哪个属性来访问数据
    例如:
    <StackPanel>
        <StackPanel.Resource>
            <sys:String x:Key="myString">
                实例本身就是数据源
            </sys:String>
        </StackPanel.Resource>
        <TextBlock x:Name="textBox1" Text="{Binding Path=.,Source={ StatciResource ResourceKey=myString}}" />
    </StackPanel>
    Path可以省略掉
    
    为Binding指定Path的几种方法
    1、普通CLR类型单个对象指定为Source:包括FCL类型和用户自定义类型的对象,如果该类型实现了INotifyPropertyChanged接口,
    则可通过在属性的set语句里激发PropertyChanged事件来通知Binding数据已被更新。
    2、数组、List<T>、ObservableCollection<T>等集合类型,一般是把控件的ItemsSource属性使用Binding关联到一个集合对象上。
    3、ADO.Net的对象DataTable和DataView对象
    4、XmlDataProvider把XML指定为Source ,如TreeView、Menu 上上节提到的x:XData指令元素
    5、把依赖对象指定为Source
    6、把容器的DataContext设为Source,只设置Path,不设置Source,让这个Binding自己去找Source(会沿着控件树一层一层向外找,直到找到带有path指定属性的对象为止)
    7、通过ElementName指定Source
    8、通过Binding的RelativeSource属性相对的指定Source:当控件想关注自己的、自己容器的或者自己内部元素的某个值时采用这种办法。
    9、把ObjectDataProvider对象指定为Source:当数据源不是通过属性而是通过方法暴漏给外界的时候
    10、使用Linq检索的数据对象作为Binding的源。
    
    一一介绍:
    6、没有Source的Binding——使用DataContext作为Binding的源
    Binding就会自动向UI元素树的上层去寻找可用的DataContext
    如下代码:
    <StackPanel>
        <StackPanel.DataContext>
            <local:Teacher Name="hailiang" Age="25" Sex="" />
        </StackPanel.DataContext>
        <Grid>
            <StackPanel>
                <TextBlock Text="{Binding Path=Name}" Margin="5"/>
                <TextBlock Text="{Binding Path=Age}" Margin="5"/>
                <TextBlock Text="{Binding Path=Sex}" Margin="5"/>
            </StackPanel>
        </Grid>
    </StackPanel>
    当实例本身就是数据源时,Path=.,可以没有path,如果某个DataContext是个简单类型对象时,也可以不指定Source
    如下代码:
    <Grid>
        <Grid.DataContext>
            <sys:String >Hello DataContext!!</sys:String>
        </Grid.DataContext>
        <StackPanel>
            <TextBlock Text="{Binding}" Margin="5"/>
        </StackPanel>
    </Grid>
    Binding沿着UI元素向上找,其实Binding没有那么智能,只是DataContext是一个依赖属性
    这里依赖属性很重要的一个特点是:
    当你没有为控件的某个依赖属性显示赋值时,控件会把自己容器的属性值借过来当做自己的属性值
    实际工作中DataContext的用法非常灵活:
    (1)、当UI上的多个控件使用Binding关注同一个对象时,可以使用DataContext。
    (2)、当作为Source的对象不能被直接访问时——比如B窗体的控件想把A窗体的控件当做自己的Binding源时,但A窗体的控件是private访问级别,这时候就可以
    把这个控件(控件的值)作为A窗体的DataContext(这个属性石public访问级别)从而暴漏出来
    
    
    2、使用集合对象作为列表控件的ItemsSource
    使用集合类型作为列表控件的ItemsSource时一般会考虑用ObserableCollection<T>代替List<T>,因为其实现了INotifyCollectionChanged和INotifyPropertyChanged接口
    能把集合的变化立刻显出来。
    
    3、使用ADO.NET做为Binding的源
    一般是
    DataTable dt=Bussiness.GetData();
    listBox1.ItemsSource=dt.DefaultView;
    这里的DefaultView是个DataView类型的对象。DataView实现了IEnumerable接口,所以可以给ItemsSource赋值。
    DataTable不能直接拿来为ItemsSource赋值
    但是可以将DataTable对象放到一个对象的DataContext属性里,并把ItemsSource与一个既没有Path有没有Source的Binding关联起来,Binding能自动找到DefaultView并
    当做自己的Source
    代码:
    DataTable dt=this.Load();
    this.listViewStudents.DataContext=dt;
    this.listViewStudents.SetBinding(ListView.ItemsSourceProperty,new Binding());
    
    GridView可以为GridViewColumn设置HeaderTemplate和CellTemplate,他们的类型都是DataTemplate。
    
    4、使用Xml数据作为Binding源
    迄今为止 .net framework提供了2套处理xml数据的类库
    1、符合DOM标准的类库:包括XmlDocument、XmlElement、XmlNode、XmlAttribute
    2、Linq:包括XDocument、XElement、XNode、XAttribute
    注意:当使用Xml作为Binding的Source时,这里讲使用XPath,而非Path
    
    XPath=@Id 这里使用@符号表示的是XML元素的Attribute
    
    把XML数据和XmlDataProvider对象直接写在XAML代码里,那么XML数据要放在<x:XData>...</x:XData>中。代码中用到HierarchicalDataTemplate
    代码如下:
    <Window.Resources>
            <XmlDataProvider x:Key="xdp" XPath="FileSystem/Folder">
                <x:XData>
                    <FileSystem xmlns="">
                        <Folder Name="Books">
                            <Folder Name="C#">
                                <Folder Name="CLR via C#" />
                                <Folder Name="C#本质论"/>
                            </Folder>
                            <Folder Name=".NET">
                                <Folder Name="Silverlight" />
                                <Folder Name="WPF" />
                            </Folder>
                            <Folder Name="DataBase">
                                <Folder Name="SQL Server 2008" />
                                <Folder Name="MySql"/>
                                <Folder Name="Oracle"/>
                            </Folder>
                        </Folder>
                    </FileSystem>
                </x:XData>
            </XmlDataProvider>
        </Window.Resources>
    <StackPanel>
        <TreeView ItemsSource="{Binding Source={StaticResource ResourceKey=xdp}}">
                <TreeView.ItemTemplate>
                    <HierarchicalDataTemplate ItemsSource="{Binding XPath=Folder}">
                        <TextBlock Text="{Binding XPath=@Name}"/>
                    </HierarchicalDataTemplate>
                </TreeView.ItemTemplate>
        </TreeView>
    </StackPanel>
    
    10、使用Linq作为Binding的源
    Linq的查询结果是个IEnumberable<T>类型的对象
    可以作为列表控件的ItemsSource来使用
    
    9、使用ObjectDataProvider作为Binding的Source
    把对象作为数据源提供给Binding
    ObjectDataProvider作用是用来包装一个以方法暴露数据的对象
    代码:
    ObjectDataProvider odp = new ObjectDataProvider();
        odp.ObjectInstance = new Calculator();
        odp.MethodName = "Add";
        odp.MethodParameters.Add("0");
        odp.MethodParameters.Add("0");
    
        Binding bindingToArg1 = new Binding("MethodParameters[0]")
        {
            Source = odp,
            //告诉Binding只负责把从UI元素收集到的数据写入Source(ObjectDataProvider对象)
             BindsDirectlyToSource=true,
             //一有更新立即传回Source
             UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged
        };
        this.txtNum1.SetBinding(TextBox.TextProperty, bindingToArg1);
    
        txtNum2.SetBinding(TextBox.TextProperty, new Binding("MethodParameters[1]")
        {
            Source = odp,
            BindsDirectlyToSource = true,
            UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
        });
    
        txtResult.SetBinding(TextBox.TextProperty, new Binding(".") { Source = odp });
    
    8、使用Binding的RelativeSource
    略 
    
    Binding对数据的转换与校验
    
    Binding在Target与Source之间起着桥梁的作用,但是桥上也有关卡,用来  数据转换盒数据校验
    数据校验:Binding的ValidationRules属性
    继承抽象类:ValidationRule,重写override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)该方法
    数据转换:Binding的Converter属性
    实现IValueConverter接口
    public infterface IValueConverter
    {
        //当数据从Binding的Source流向Target时Converter被调用
        /**
         *参数1:未转型之前的值
         *参数2:确定方法的返回类型,outputType
         *参数3:把额外的信息传入方法
         *另外Binding的Model属性会影响这2个方法的调用
         */
        object Converter(object value,Type targetType,object parameter,CultureInfo culture);
        //当数据从Binding的Target流向Source时ConverterBack被调用
        object ConvertBack(object value,Type targetType,object parameter,CultureInfo culture);
    }
    
    
    MultiBinding
    与Binding一样都是以BindingBase为基类
    其有个属性Bindings类型为Collection<BindingBase>
    例如,注册用户时有重复输入用户名或密码,来控制提交按钮的启用与禁用
    Converter:
    class LogonMultiBindingConverter:IMultiValueConverter    //实现的是IMultiBindingConverter接口
        {
            public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                //throw new NotImplementedException();
                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, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    后台代码:
        Binding b1 = new Binding("Text") { Source=txt1 };
        Binding b2 = new Binding("Text") { Source = txt2 };
        Binding b3 = new Binding("Text") { Source = txt3 };
        Binding b4 = new Binding("Text") { Source = txt4 };
    
        MultiBinding bindings = new MultiBinding() { Mode=BindingMode.OneWay};
        //MultiBinding对添加子级Binding的顺序是敏感的
        bindings.Bindings.Add(b1);
        bindings.Bindings.Add(b2);
        bindings.Bindings.Add(b3);
        bindings.Bindings.Add(b4);
    
        bindings.Converter = new LogonMultiBindingConverter();
    
        btnSubmit.SetBinding(Button.IsEnabledProperty, bindings);
        
        
  • 相关阅读:
    Asp.Net Core 3.1 使用Autofac Aop
    Abp中的工作单元UnitOfWork的Aop是如何实现的
    Asp.Net Core 3.1 Api 集成Abp项目AutoMapper
    Asp.Net Core 3.1 Api 集成Abp项目动态WebApi
    php限制登录次数
    vbs小实例
    php导出数据到excel
    mysqli单例模式连接数据库
    微信JsApi支付
    HTML5新增表单控件
  • 原文地址:https://www.cnblogs.com/hailiang2013/p/3035348.html
Copyright © 2011-2022 走看看