winform有binding, WPF也有binding,区别在哪呢?这里暂时不提。以前也检查接触WPF binding, 但为什么过段时间就忘记了呢?

可能主要原因自己的知识体系不够完善吧,下面我先总结下binding的用法,然后再深入挖掘binding的原理,最后再总结,这样希望自己能够对binding达到非常深刻的理解。

binding的用法:

  1)绑定控件属性。下面是将一个Slider的值绑定到一个Textbox上。

     <TextBox Grid.Row="1" Text="{Binding Path=Value,ElementName=slider1}"></TextBox>
            <Slider Grid.Row="2" x:Name="slider1" Maximum="100" Minimum="0"></Slider>

2)绑定多级路径,比如属性的属性,索引器等。

      <TextBox Grid.Row="2" x:Name="textbox2" Text="{Binding  Path=Text.Length,ElementName=textbox1,Mode=OneWay}"
                     BorderBrush="Black" Margin="5"></TextBox>
            <TextBox Grid.Row="3" x:Name="textbox3" Text="{Binding Path=Text[4],ElementName=textbox1,Mode=OneWay}"
                     BorderBrush="Red" Margin="5"></TextBox>

3)还可以判定集合,甚至是集合的集合元素。

      List<string> stringList = new List<string>(){"xiaowang","dabing","qizhi"};
            this.txtCollection1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = stringList });
            this.txtCollection2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = stringList,
                Mode = BindingMode.OneWay });
            this.txtCollection3.SetBinding(TextBox.TextProperty, new Binding("/[2]") { Source = stringList, Mode = BindingMode.OneWay });

this.txtCollection4.SetBinding(TextBox.TextProperty, new Binding("/Name") { Source = countryList });
            this.txtCollection5.SetBinding(TextBox.TextProperty, new Binding("/ProvinceList/Name")
            {
                Source = countryList,
            });
            this.txtCollection6.SetBinding(TextBox.TextProperty, new Binding("/ProvinceList/CityList/Name") { Source = countryList });

4)还可以没有Path的Binding,这里的路径直接用一个.就可以了。

<TextBox Grid.Row="1" Text="{Binding .,Source={StaticResource ResourceKey=myString}}"></TextBox>

5)使用DataContext作为源:

<StackPanel Grid.Row="1">
                <StackPanel.DataContext>
                    <local:Student Id="4" Age="18" Name="Jim"></local:Student>
                </StackPanel.DataContext>
                <TextBox Text="{Binding Path=Id}" Margin="5"/>
                <TextBox Text="{Binding Path=Name}" Margin="5"/>
                <TextBox Text="{Binding Path=Age}" Margin="5"/>
            </StackPanel>

6)为列表控件指定ItemsSource

List<Student> stuList = new List<Student>()
            {
                new Student(){ Age = 18, Id = 1, Name = "Xiao"},
                new Student(){ Age = 19, Id = 4, Name = "smao"},
                new Student(){ Age = 20, Id = 3, Name = "duo"},
                new Student(){ Age = 21, Id = 2, Name = "shao"},
            };
            this.listBoxStudents.ItemsSource = stuList;
            this.listBoxStudents.DisplayMemberPath = "Name";
            Binding binding = new Binding("SelectedItem.Id") { Source = this.listBoxStudents };
            this.txtId.SetBinding(TextBox.TextProperty, binding);
            this.listBoxStudents.SelectedIndex = 0;

7)为列表控件指定外衣来绑定集合,绑定的代码是一样的。

<ListBox x:Name="listBoxStudents2" Grid.Row="4">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Text="{Binding Path=Id}" Width="30"/>
                            <TextBlock Text="{Binding Path=Name}" Width="60"/>
                            <TextBlock Text="{Binding Path=Age}" Width="30"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

8)DataTable作为源。

      <StackPanel Grid.Row="1">
                <ListView x:Name="listViewStudents">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Header="Id" Width="60" DisplayMemberBinding="{Binding Path=Id}"/>
                            <GridViewColumn Header="Name" Width="80" DisplayMemberBinding="{Binding Path=Name}"/>
                            <GridViewColumn Header="Age" Width="60" DisplayMemberBinding="{Binding Path=Age}"/>
                        </GridView>
                    </ListView.View>
                </ListView>
            </StackPanel>

this.listViewStudents.ItemsSource = dt.DefaultView;

9)把类的方法包装成数据作为源ObjectDataProvider

ObjectDataProvider odp = new ObjectDataProvider();

odp.ObjectInstance = new Calculator();//方法类

odp.MethodName = "Add"; //方法名

odp.MethodParameters.Add("0"); //添加方法参数

odp.MethodParameters.Add("1");

Binding bindingToArg1 =  new Binding("MethodParameters[0]")

{ Source = odp,    BindsDirectlyToSource = true,

UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };

Binding bindingToArg2 = new Binding("MethodParameters[1]")

{ Source = odp,    BindsDirectlyToSource = true,

UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };

Binding bindingToResult = new Binding(".") { Source = odp };

txtArg1.SetBinding(TextBox.TextProperty, bindingToArg1);//把控件当做目标,源是最终的方法类

txtArg2.SetBinding(TextBox.TextProperty, bindingToArg2);

txtResult.SetBinding(TextBox.TextProperty, bindingToResult);//控件依然是目标,如果是.就是provider的数据

10)自身控件或者上级控件的属性作为源的。

<Grid Grid.Row="2" Grid.Column="2" Background="Black" Margin="15">
            <DockPanel x:Name="Dock" Background="Blue" Margin="20">
                <Grid Background="Orange" Margin="20">
                    <StackPanel>
                        <TextBox Text="{Binding Path=Name, RelativeSource={RelativeSource AncestorLevel=1,AncestorType= {x:Type DockPanel}}}" Margin="0"></TextBox>
                        <TextBox x:Name="txt1" Text="{Binding Path=Name, RelativeSource={RelativeSource Mode=Self}}" Margin="0"></TextBox>
                    </StackPanel>
                </Grid>
            </DockPanel>
        </Grid>

11)使用XML数据作为Binding源。

  12)使用LINQ检索结果作为Binding的源。

  13)binding的数据校验:

private void BindingValidation()
        {
            Binding binding = new Binding("Value") { Source = sliderValidation, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged };
            RangeValidationRule rvr = new RangeValidationRule();
            rvr.ValidatesOnTargetUpdated = true;
            binding.NotifyOnValidationError = true;
            binding.ValidationRules.Add(rvr);
            this.txtValidation.SetBinding(TextBox.TextProperty, binding);
            this.txtValidation.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));
        }
        private void ValidationError(object sender, RoutedEventArgs e)
        {
            if (Validation.GetErrors(this.txtValidation).Count > 0)
            {
                this.txtValidation.ToolTip = Validation.GetErrors(this.txtValidation)[0].ErrorContent.ToString();
            }
        }

14)binding的转换:

     <ListBox x:Name="listBoxConvert" Grid.ColumnSpan="2">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Width="20" Height="20" Source="{Binding Path=Category,Converter={StaticResource cts}}"></Image>
                            <TextBlock Text="{Binding Path=Name}" Width="60" Margin="80,0"></TextBlock>
                            <CheckBox IsThreeState="True" IsChecked="{Binding Path=State,Converter={StaticResource stnb}}"></CheckBox>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>

public class CategoryToSourceConverter : IValueConverter

{

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{

Category c = (Category)value;

switch (c)

{

case Category.Bomber:

return @"\Images\Bomber.jpg";

case Category.Fighter:

return @"\Images\Fighter.jpg";

default:                     return null;

}             //throw new NotImplementedException();         }

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{             throw new NotImplementedException();         }

}

public class StateToNullableBoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            State s = (State)value;
            switch (s)
            {
                case State.Available:
                    return true;
                case State.Locked:
                    return false;
                default:
                    return null;
            }
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool? nb = (bool?)value;
            switch (nb)
            {
                case true:
                    return State.Available;
                case false:
                    return State.Locked;
                case null:
                default:
                    return State.Unknown;
            }
        }
    }

15)多路binding:

     public void SetMultiBinding()
        {
            Binding b1 = new Binding("Text") { Source = this.txtMult1 };
            Binding b2 = new Binding("Text") { Source = this.txtMult2 };
            Binding b3 = new Binding("Text") { Source = this.txtMult3 };
            Binding b4 = new Binding("Text") { Source = this.txtMult4 };
            MultiBinding mb = new MultiBinding() { Mode = BindingMode.OneWay };
            mb.Bindings.Add(b1);
            mb.Bindings.Add(b2);
            mb.Bindings.Add(b3);
            mb.Bindings.Add(b4);
            mb.Converter = new LogonMultiBindingConverter();
            this.btnSubmit.SetBinding(Button.IsEnabledProperty, mb);
        }

public class LogonMultiBindingConverter : IMultiValueConverter

{

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.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, System.Globalization.CultureInfo culture)         {             throw new NotImplementedException();         }     }

  16. Binding的BindingMode:

     <Slider x:Name="sliderMode" Grid.Row="1" Grid.ColumnSpan="2" Value="48" Minimum="0" Maximum="100"></Slider>
            <TextBlock Grid.Row="2" Text="OneWay:"></TextBlock>
            <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Path=Value, Mode=OneWay, ElementName=sliderMode}"></TextBox>
            <TextBlock Grid.Row="3" Text="TwoWay:"></TextBlock>
            <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Path=Value, Mode=TwoWay, ElementName=sliderMode}"></TextBox>
            <TextBlock Grid.Row="4" Text="OneTime:"></TextBlock>
            <TextBox Grid.Row="4" Grid.Column="1" Text="{Binding Path=Value, Mode=OneTime, ElementName=sliderMode}"></TextBox>
            <TextBlock Grid.Row="5" Grid.Column="0" Text="OneWayToSource:"></TextBlock>
            <TextBox Grid.Row="5" Grid.Column="1" Text="{Binding Path=Value, Mode=OneWayToSource, ElementName=sliderMode}"></TextBox>
            <TextBlock Grid.Row="6" Text="Default:"></TextBlock>
            <TextBox Grid.Row="6" Grid.Column="1" Text="{Binding Path=Value, Mode=Default, ElementName=sliderMode}"></TextBox>

在讲完binding的使用后,我们接下来深入剖析下binding:

首先看一看binding的一些重要成员:

  binding的源:

    1)RelativeSource。相对资源。 

    2)ElementName:元素名,在指定源的时候,如果是控件,可以指定这个。 

       3)Source:指定binding的源。

4)StaticSource:静态资源. 

  Path: PropertyPath类型,指定源的路径。

  bindingMode:指定绑定的模式。

    1)TwoWay.目标和源都可以影响对方。

    2) OneWay.只有源影响目标。

    3)OneTime.只有程序启动时或者DataContext进行更改时更新目标属性。

    4)OneWayToSource.在目标属性更改时更新源属性。

    5)Default.使用目标属性的默认Mode值。比如TextBox.Text就是双向的,TextBlock.Text就是单向的。

  UpdateSourceTrigger:指定源更新的时期

    1)PropertyChanged. 属性变化的时候更新

    2)LostFocus. 失焦的时候更新。

    3)Explicit.

    4)Default. 缺省。

  NotifyOnSourceUpdated NotifyOnTargetUpdated 这两个Bool属性。

    如果为true表示当源或者目标更新后binding会激发相应的SourceUpdated和TargetUpdated事件。

    实际工作中,我们可以监听这两个事件来找出有哪些数据或者控件被更新了。

ValidationRules.

     ValidationRule的对象集合,这里是指定绑定的验证规则,在进行验证的时候,默认都是认为来自source的数据总是正确的,不需要验证,如果需要验证就要

  设置ValidatesOnTargetUpdated(因为source是会引起Target更新),如果验证的时候的错误需要发出去,需要设置NotifyOnValidationError属性为true,那么

  这个信号就会以binding对象的target为起点在UI树上传播。

Converter.

    数据转换功能,当源与目标的数据类型不一样的时候,就需要使用。需要实现IValueConverter接口,

    其中:

      Convert是转换源到目标。

      ConvertBack:转换目标到源。

到这里为止,我可能还只是对binding的使用有了一个大致的了解,binding与依赖属性,依赖对象之间的关系如何,为什么binding了以后,数据驱动的原理是什么?这些都是一个疑问,我这里只是大致了解了一些类:

Binding是BindingBase的子类。BindingExpression是BindingExpressionBase的子类,BindingOperations是一个静态类。

我这样大致猜想一下:当我们Binding的时候,把源和目标绑定在一起,目标必须是依赖对象,源可以是依赖对象也可以是一般的对象,但必须公开了属性。Binding完成后,如果源是依赖属性或者一般类实现了INotifyPropertyChanged接口,那么肯定就会在弱引用管理器中添加监听者与监听对象,当属性有改变的时候,就会触发相应的事件,使得数据同步得到更新,如果一般的类没有实现这个接口,自然是得不到更新的。

  知道了这些原理,自然就知道了在不同的设置下面源于目标如何发生变化的情况:

  假设源是一个A类对象,其属性P1触发了事件PropertyChanged,P2没有触发事件PropertyChanged,假设分别绑定到了控件C1,C2。

我们来分析一下不同模式下的情况:

  OneWay: P1改变会影响C1,P2改变不会影响C2,C1改变不会影响P1,C2改变不会影响P2。

  TwoWay: P1与C1相互影响,P2与C2互不影响。

  OneTime: P1只会影响C1一次,P2与C2互不影响,C1改变不会影响P1。

  OneWayToSource: P1改变不会影响C1,P2改变不会影响C2,C1改变影响P1,C2改变不会影响P2。

  另外假设源是一个依赖对象,其依赖属性作为路径,那么其在不同模式下的情况就跟上面的假设中P1与C1的情况是一样的。

代码如下

http://files.cnblogs.com/files/monkeyZhong/WPFBindingDemo.zip

    

WPF Binding的更多相关文章

  1. WPF binding 参考

    Introduction This is an article on WPF Binding Cheat Sheet. Some of the Binding won't work for Silve ...

  2. WPF入门教程系列(二) 深入剖析WPF Binding的使用方法

    WPF入门教程系列(二) 深入剖析WPF Binding的使用方法 同一个对象(特指System.Windows.DependencyObject的子类)的同一种属性(特指DependencyProp ...

  3. WPF Binding值转换器ValueConverter使用简介(二)-IMultiValueConverter

    注: 需要继承IMultiValueConverter接口,接口使用和IValueConverter逻辑相同. 一.MultiBinding+Converter 多值绑定及多值转换实例 当纵向流量大于 ...

  4. WPF Binding值转换器ValueConverter使用简介(一)

    WPF.Silverlight及Windows Phone程序开发中往往需要将绑定的数据进行特定转换,比如DateTime类型的时间转换为yyyyMMdd的日期,再如有一个值是根据另外多组值的不同而异 ...

  5. WPF Binding Mode,UpdateSourceTrigger

    WPF 绑定模式(mode) 枚举值有5个1:OneWay(源变就更新目标属性)2:TwoWay(源变就更新目标并且目标变就更新源)3:OneTime(只根据源来设置目标,以后都不会变)4:OneWa ...

  6. WPF Binding ElementName方式无效的解决方法--x:Reference绑定

    原文:WPF Binding ElementName方式无效的解决方法--x:Reference绑定 需求: 背景:Grid的有一个TextBlock name:T1和一个ListBox,ListBo ...

  7. UpdateSourceTrigger Property in WPF Binding

    介绍 这篇文章我将介绍在WPF和Silverlight中更新绑定源的概念.正如您所知道的,当我们用TwoWay的模式绑定时,任何在目标控件上发生的变化都会影响绑定源的值. 请注意只是在用TwoWay绑 ...

  8. .NET: WPF Binding对数据的校验和转换以及多路Binding

    一.校验 一般需要对target上的值进行校验. xaml: <Window x:Class="WpfApplication1.MainWindow" xmlns=" ...

  9. WPF Binding学习(二)

    Binding作为数据的桥梁,连通业务逻辑层的对象(源对象)和UI的控件对象(目标对象).在这座桥梁上,我们不仅可以控制在源对象与目标对象是双向通行还是单向通行.还可以控制数据的放行时机,甚至可以在这 ...

随机推荐

  1. MFC任务管理器task manager----进程的挂起与恢复--NtSuspendProcess&&NtResumeProcess

    http://hi.baidu.com/xbbsh/blog/item/b73d3125462201084c088db1.html ---------------------------------- ...

  2. 追踪CM_CONTROLCHANGE消息的产生和执行过程,可以较好的领会VCL的思想(就是到处通知,但耦合性很弱)

    追踪CM_CONTROLCHANGE消息的流向,可以较好的 测试代码: procedure TForm1.Button1Click(Sender: TObject);var Image2 : TIma ...

  3. java学习之数组排序一:选择排序

    在讲完java中数组定义的两种方式之外,这里需要讲一下对数组常用的方法,第一个就是排序. 加入我们现在有个数组:int[] arr = {12,87,34,3,98,33,103}; 思路1: 1.首 ...

  4. Linux Shell编程(7)——变量赋值

    =赋值操作符(它的左右两边不能有空白符) 不要搞混了=和-eq,-eq是比赋值操作更高级的测试.注意:等于号(=)根据环境的不同它可能是赋值操作符也可能是一个测试操作符.例子:简单的变量赋值 #!/b ...

  5. ZOJ 3469 Food Delivery

    题目大意: 有n个人,住在一条直线上.第i个人的坐标是Xi,街上有个外卖餐馆的位置是X,现在餐厅工作人员要给街上的每个人送饭,送完之后再回到餐厅,送饭人的速度是V,每个人有个不满意值,当这个人送餐时间 ...

  6. POJ 3180 The Cow Prom(强联通)

    题目大意: 约翰的N(2≤N≤10000)只奶牛非常兴奋,因为这是舞会之夜!她们穿上礼服和新鞋子,别上鲜花,她们要表演圆舞.           只有奶牛才能表演这种圆舞.圆舞需要一些绳索和一个圆形的 ...

  7. OC中的野指针(僵尸指针)

    涉及到内存管理问题的都是类类型的变量,而在OC中我们操纵这些对象都是通过操纵指向他们的指针来完成的,一致很多时候会忽略指针存在.比如定义UIView * view = [[UIView alloc]i ...

  8. svn server安装配置

    安装平台:RHEL5 1.安装软件:httpd.subversion.mod_dav_svn 2.修改配置 修改/etc/httpd/conf.d/subversion.conf.eg: LoadMo ...

  9. Jack Straws(判断线段是否相交 + 并查集)

    /** http://acm.tzc.edu.cn/acmhome/problemdetail.do?&method=showdetail&id=1840    题意:    判断线段 ...

  10. [工具] Numpy

    虽说功能强大,要什么基本都有,但感觉它提供的功能还不如Matlab好记呢...Anyway,首先import numpy as np 1. 操作基本单元,矩阵 np.array(list) / np. ...