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. 静态与动态IP设置

    静态IP设置 netsh interface ipv4 set address name="本地连接" source=static addr=192.168.0.212 (这个地方 ...

  2. Linux日志文件系统(EXT4、XFS、JFS)及性能分析

    Ext4 ReiserFS Btrfs 等七种文件系统性能比拼 自上一篇<Ext2 v.s. Ext3 v.s. Ext4 性能比拼> 发布以来,社会各界纷纷来电来函,给出了“Ext4 我 ...

  3. Paths on a Grid

    http://poj.org/problem?id=1942 题意:一个n*m的格子,从左下角走到右上角有多少种走法,规定只能向上或向右走: 思路:解法挺水的,高中学组合数的时候老师给讲过:求C[m+ ...

  4. 「Poetize6」Candle

    描述 蜡烛商店中有10种蜡烛,形状分别是0~9这10个数字,不过对于每种蜡烛,商店的存货量仅有一根.另外,忘川沧月已经有了一个"+"形状的蜡烛.忘川沧月想购买一些蜡烛,使得他的家族 ...

  5. 字符串(后缀自动机):COGS 2399. 循环同构

    这道题直接看代码吧. #include <iostream> #include <cstring> #include <cstdio> using namespac ...

  6. 图论(2-sat):Priest John's Busiest Day

    Priest John's Busiest Day   Description John is the only priest in his town. September 1st is the Jo ...

  7. 什么是Socket,为什么要用Socket

    应用层通过传输层进行数据通信时,TCP和UDP会遇到同时为多个应用程序进程提供并发服务的问题.多个TCP连接或多个应用程序进程可能需要通过同一个TCP协议端口传输数据.为了区别不同的应用程序进程和连接 ...

  8. Codeforces Round #324 (Div. 2)解题报告

    ---恢复内容开始--- Codeforces Round #324 (Div. 2) Problem A 题目大意:给二个数n.t,求一个n位数能够被t整除,存在多组解时输出任意一组,不存在时输出“ ...

  9. poj3122

    题目大意:馅饼(看起来像是一个简单点的题目啊,嘎嘎,希望是的吧) 我的生日即将来临按照习惯我将准备馅饼,不是一个馅饼,我有N块馅饼,有各种各样的味道和尺寸,当我的朋友来参加我的聚会平且他们都能得到一块 ...

  10. + (void)load和+ (void)initialize有什么用处

    两个方法都可以进行一些类的初始化操作.其中有些小区别.+(void)load 方法只要加入了工程种,进行了编译,且.m中实现了这个方法,都会调用一次,值得注意的时没实现的子类是不会调用的,就算父类实现 ...