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. window7 64位安装Python

    Python下载地址:https://www.python.org/download/releases/2.7.8/ 选择64位的安装,然后双击打开下载的文件,默认一步步安装. 其中有一个步骤如下图: ...

  2. 1A Theatre Square

    题目大意; 有一个广场,广场的大小是n*m,  有a*a的石砖,石砖铺广场可以比广场大,石砖不能切割.问最少需要多少个石砖. ===================================== ...

  3. Redis源码阅读笔记(2)——字典(Map)实现原理

    因为redis是用c写的,c中没有自带的map,所以redis自己实现了map,来看一下redis是怎么实现的. 1.redis字典基本数据类型 redis是用哈希表作为字典的底层实现,dictht是 ...

  4. C字符数组及其应用

    1.字符数组和其他数值类型的数组的定义引用和初始化都是相同的. 特别注意的是: 在C语言中没有专门的字符串变量,通常用一个字符数组来存放一个字符串. \0'是由C编译系统自动加上的. 2. C语言允许 ...

  5. UNIX环境下的消息队列

    消息队列和共享内存一样,也是一种IPC对象.消息队列其实就是消息的链表,每一则消息都是用户自己的结构体.服务端这边创建消息队列,客户端这边打开消息队列,两个进程就可以进行通信.创建和打开消息队列使用函 ...

  6. [Java] JavaMail 发送 html 格式、带附件的邮件

    本案例演示发送 html 格式,可带附件的邮件发送.发送纯文本邮件的例子可参照上一篇博文JavaMail 简单案例. EmailHelper, Email 的帮助类,向帮助类提供 SMTP 服务器域名 ...

  7. poj 1236强连通图缩点

    题目链接:http://poj.org/problem?id=1236 #include <cstdio> #include <cmath> #include <algo ...

  8. 使用JAVA与SmartFoxServer来实现游戏服务器概述

    SmartFoxServer 是专门为Adobe Flash设计的跨平台socket服务器,让开发者高效地开发多人应用及游戏. 该服务器主要用来创建多玩家游戏.并提供强大的制作工具,各种回合制游戏和实 ...

  9. Spring MVC返回对象JSON

    @RestController 用于返回对象,会自动格式化为JSON     @RequestMapping("/user2")     public User2 user2(Mo ...

  10. tyvj1728 普通平衡树

    为了彻底理解树状数组,试着用树状数组做了下普通平衡树 而树状数组只能离线做,或者保证值的大小在数组可承受的范围内也是可以的,因为要求离线是因为必须事前对所有数离散化. 然后我们看刘汝佳蓝书上的图 利用 ...