原创,转载请注明出处:WPF DataBinding之我见

一、DataBinding介绍

  数据绑定是在应用程序 UI 与业务逻辑之间建立连接的过程。 如果绑定具有正确设置并且数据提供正确通知,则当数据更改其值时,绑定到数据的元素会自动反映更改。 数据绑定可能还意味着如果元素中数据的外部表现形式发生更改,则基础数据可以自动更新以反映更改。 例如,如果用户编辑 TextBox 元素中的值,则基础数据值会自动更新以反映该更改。下图表示Binding模型:

   其中,Binding目标必须是依赖对象,XAMAL控件都继承自DependencyObject,若想自定义的类的对象也能成为Binding目标,则该类必须继承自DependencyObject。依赖对象类里面有个依赖属性注册类,调用该注册类就能声明一个依赖属性,之后再定义类似于CLR公共属性的操作(get与set需要调用特定函数,具体实现参考后面示例 )。

  Binding数据源则无限制,可以是CLR属性或者XAMAL控件,也可以是自定义依赖对象的依赖属性或者是继承自INotifyPropertyChanged的类对象属性。普通CLR属性不具备当自身发生改变时自动通知目标数据的功能,而依赖属性以及继承自INotifyPropertyChanged的类对象属性就具备此功能。

  目标与数据源的联系是通过Binding对象实现的。Binding是一个特殊类,能够设置绑定的数据流方向(OneWay、TwoWay、OneWayToSource)、数据转换器(当数据源与目标数据类型不匹配时,包括双向转换)、校验器、数据更新方式等。

  下面就通过三种数据绑定方式来进一步了解DataBinding。

二、控件间的DataBinding

  XAMAL控件都是继承自DependencyObject,故控件间的依赖属性可以互相绑定,即可当做源也可作为目标,三种数据流方向都可设定,另外还可设定数据更新方式。不同控件一般会有不同的默认数据流方向,TwoWay方式下两个方向的数据更新方式会不大一样,一般从源到目标是PropertyChanged,从目标到源则是LostFocus。使用示例如下:

  XAMAL文件:

<Window x :Class="DataBinding_controls.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height ="350" Width="525">
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width ="2*" />
<ColumnDefinition Width ="4*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height ="*" />
<RowDefinition Height ="*" />
<RowDefinition Height ="*" />
</Grid.RowDefinitions>
<TextBlock Grid.RowSpan ="3" TextWrapping="Wrap"> 数据绑定方式演示, <LineBreak /> 其中数据的更新方式UpdateSourceTrigger默认为LostFocus, 另外还有Explicit以及PropertyChanged <LineBreak /> 第三个示例就使用了PropertyChanged </TextBlock>
<StackPanel Grid.Row ="0" Grid.Column = "1" Orientation="Horizontal">
<TextBlock> OneWay:============== </TextBlock >
<StackPanel>
<TextBlock FontSize ="12" Foreground="Red"> Source</TextBlock >
<TextBox x :Name="txb1"> Hello1</TextBox >
</StackPanel>
<StackPanel>
<TextBlock FontSize ="12" Foreground="Red"> --》Target</TextBlock >
<TextBox Text ="{Binding Path =Text,ElementName=txb1, Mode=OneWay}"/>
</StackPanel>
</StackPanel>
<StackPanel Grid.Row ="1" Grid.Column = "1" Orientation="Horizontal">
<TextBlock> TwoWay(TextBlock Default):==</TextBlock >
<StackPanel>
<TextBlock FontSize ="12" Foreground="Red"> Source</TextBlock >
<TextBox x :Name="txb2"> Hello2</TextBox >
</StackPanel>
<StackPanel>
<TextBlock FontSize ="12" Foreground="Red"> 《==》Target</TextBlock >
<TextBox Text ="{Binding Path =Text,ElementName=txb2, Mode=TwoWay}"/>
</StackPanel>
</StackPanel>
<StackPanel Grid.Row ="2" Grid.Column = "1" Orientation="Horizontal">
<TextBlock> OneWayToSource:======== </TextBlock >
<StackPanel>
<TextBlock FontSize ="12" Foreground="Red"> Source </TextBlock >
<TextBox x :Name="txb3"> Hello3</TextBox >
</StackPanel>
<StackPanel>
<TextBlock FontSize ="12" Foreground="Red"> 《--Target</TextBlock >
<!--以下绑定在cs代码中实现-->
<TextBox x :Name ="xxj"/>
</StackPanel>
</StackPanel>
</Grid >
</Window>

  后台CS文件:

using System ;
using System .Collections. Generic;
using System .Linq;
using System .Text;
using System .Threading. Tasks;
using System .Windows;
using System .Windows. Controls;
using System .Windows. Data;
using System .Windows. Documents;
using System .Windows. Input;
using System .Windows. Media;
using System .Windows. Media.Imaging ;
using System .Windows. Navigation;
using System .Windows. Shapes; namespace DataBinding_controls
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow ()
{
InitializeComponent(); //Binding binding = new Binding();
////设置源对象
//binding.Source = txb3;
////设置源属性
//binding.Path = new PropertyPath("Text");
//binding.Mode = BindingMode.OneWayToSource;
//binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
////添加到目标属性
//xxj.SetBinding(TextBox.TextProperty, binding); //以上操作等价于以下两句
Binding binding = new Binding( "Text") { Source = txb3, Mode = BindingMode.OneWayToSource , UpdateSourceTrigger = UpdateSourceTrigger. PropertyChanged};
xxj. SetBinding(TextBox .TextProperty, binding); //等价于BindingOperations.SetBinding(xxj, TextBox.TextProperty, binding);
}
}
}

三、自定义数据源实现INotifyPropertyChanged

  INotifyPropertyChanged是一个系统的接口类,里面只是定义了一个事件,该事件用于当属性值发生改变时通知Binding目标。普通类的CLR属性并不具备自动通知功能,依赖对象的依赖属性则是自动包含了此功能。若想自定义类的属性能够实现自动通知更改但又不想让该类变为依赖类,则可让该类继承INotifyPropertyChanged接口,这样就能保证普通CLR属性具备自动通知更改的能力。使用示例如下:

  XAMAL文件:

<Window x :Class="Databinding_INotifyPropertyChanged.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height ="350" Width="525">
<StackPanel Margin="20">
<TextBlock Width ="40" Height="20" HorizontalAlignment="Left">Name: </TextBlock>
<TextBox Width ="100" HorizontalAlignment="Left" Text="{Binding Name, Mode =OneWay}"/>
<TextBlock Width ="40" Height="20" HorizontalAlignment="Left">Age: </TextBlock>
<TextBox Width ="100" HorizontalAlignment="Left" Text="{Binding Age, Mode =TwoWay}"/>
<Button Content ="随机替换年龄" Width="100" HorizontalAlignment ="Left" Click="Button_Click"/>
</StackPanel >
</Window>

  后台CS文件:

using System ;
using System .Collections. Generic;
using System .Linq;
using System .Text;
using System .Threading. Tasks;
using System .Windows;
using System .Windows. Controls;
using System .Windows. Data;
using System .Windows. Documents;
using System .Windows. Input;
using System .Windows. Media;
using System .Windows. Media.Imaging ;
using System .Windows. Navigation;
using System .Windows. Shapes;
using System .ComponentModel; namespace Databinding_INotifyPropertyChanged
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public Student stu = new Student( "xiao ming", 12); public MainWindow ()
{
InitializeComponent(); this.DataContext = this.stu;
stu.PropertyChanged += sourceDataChanged; } void sourceDataChanged (object sender, PropertyChangedEventArgs e)
{
MessageBox.Show (e.PropertyName. ToString() + "改变" );
} private void Button_Click( object sender , RoutedEventArgs e)
{ Random test = new Random();
stu.Age = Convert. ToInt32(test .NextDouble() * 100);
}
} public class Student : INotifyPropertyChanged
{
public Student (string _name, int _age)
{
this.name = _name;
this.age = _age;
}
private string name;
public string Name
{
get
{
return this .name;
}
set
{
if (this .name != value)
{
this.name = value;
OnProperyChanged("Name" );
}
}
}
private int age;
public int Age
{
get
{
return this .age;
}
set
{
if (this .age != value)
{
this.age = value;
OnProperyChanged("Age" );
}
}
} //系统自动添加往PropertyChanged添加委托,参考http://www.xxbar.net/thread-706561-1-1.html
public event PropertyChangedEventHandler PropertyChanged; public void OnProperyChanged( string propertyName )
{
if (PropertyChanged != null)
{
PropertyChanged(this , new PropertyChangedEventArgs( propertyName));
}
}
}
}

四、自定义DependencyObject

  依赖对象里面包含依赖属性,依赖属性一方面可以节省对象占用空间,另一方面可以通过数据绑定从其他对象的属性中实时获取数值,具体来龙去脉参考WPF基础入门(4)-什么是依赖属性

  普通CLR属性可以通过作为数据源并设定数据流方式为TwoWay获取客户端某个控件的值,示例如下:

  XAMAL文件:

<Window x :Class="DataBinding_DependencyObject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height ="150" Width="200">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height ="25"/>
<RowDefinition Height ="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width ="20"/>
<ColumnDefinition Width ="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row ="0" Grid.Column="0"> B:</TextBlock >
<TextBox Name ="txbB" Width="120" Grid.Row="1" Grid.Column ="1" Text="jjj"/>
<Button Grid.Row ="1" Grid.ColumnSpan="2" Click="Button_Click">点击查看内部对象值 </Button>
</Grid >
</Window>

  后台CS文件:

using System .Text;
using System .Threading. Tasks;
using System .Windows;
using System .Windows. Controls;
using System .Windows. Data;
using System .Windows. Documents;
using System .Windows. Input;
using System .Windows. Media;
using System .Windows. Media.Imaging ;
using System .Windows. Navigation;
using System .Windows. Shapes; namespace DataBinding_DependencyObject
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public school longZhong; public MainWindow ()
{
InitializeComponent(); DataContext = this ; longZhong = new school(); Binding binding = new Binding( "Name") { Source = longZhong, Mode = BindingMode .TwoWay };
BindingOperations.SetBinding (txbB, TextBox. TextProperty, binding );
} private void Button_Click( object sender , RoutedEventArgs e)
{
if (longZhong != null)
{
MessageBox.Show (longZhong. Name);
}
}
} public class school
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
}

  继承了INotifyPropertyChanged接口的类属性在此基础上还能提供更改通知。但这种数据获取方式毕竟有所限制,最起码你必须设定为TwoWay。此限制的根本原因在于普通CLR属性以及继承了INotifyPropertyChanged接口的类属性不能作为Binding目标(setBinding接口的Binding目标必须是DependencyObject类型)。为了打破限制,用户可以自定义依赖类(只需继承DependencyObject),这样其对象的依赖属性就能和普通控件属性一样随意设置各种绑定方式,并且同样具备自动通知更改的能力。使用示例如下:

  XAMAL文件:

<Window x :Class="DataBinding_DependencyObject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height ="150" Width="200">
<Grid Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height ="25"/>
<RowDefinition Height ="25"/>
<RowDefinition Height ="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width ="20"/>
<ColumnDefinition Width ="*"/>
</Grid.ColumnDefinitions>
<TextBlock> A:</TextBlock >
<TextBox Name ="txbA" Width="120" Grid.Column="1" Text =" uu"/>
<TextBlock Grid.Row ="1" Grid.Column="0"> B:</TextBlock >
<TextBox Name ="txbB" Width="120" Grid.Row="1" Grid.Column ="1" Text="jjj"/>
<Button Grid.Row ="2" Grid.ColumnSpan="2" Click="Button_Click">点击查看内部对象值 </Button>
</Grid >
</Window>

  后台CS文件:

using System ;
using System .Collections. Generic;
using System .Linq;
using System .Text;
using System .Threading. Tasks;
using System .Windows;
using System .Windows. Controls;
using System .Windows. Data;
using System .Windows. Documents;
using System .Windows. Input;
using System .Windows. Media;
using System .Windows. Media.Imaging ;
using System .Windows. Navigation;
using System .Windows. Shapes; namespace DataBinding_DependencyObject
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public school longZhong; public MainWindow ()
{
InitializeComponent(); DataContext = this ; longZhong = new school();
Binding binding = new Binding( "Text") { Source = txbA, Mode = BindingMode.TwoWay };
BindingOperations.SetBinding (longZhong, school.NameProperty , binding); Binding binding1 = new Binding( "Name") { Source = longZhong, Mode = BindingMode .TwoWay };
BindingOperations.SetBinding (txbB, TextBox. TextProperty, binding1 );
} private void Button_Click( object sender , RoutedEventArgs e)
{
//school hh = new school();
//hh.Name = txbA.Text;
if (longZhong != null)
{
MessageBox.Show (longZhong. Name);
}
}
} public class school : DependencyObject
{
public string Name
{
get { return (string) GetValue(NameProperty ); }
set { SetValue (NameProperty, value); }
} // Using a DependencyProperty as the backing store for Name. This enables animation, styling, binding, etc...
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register ("Name", typeof(string ), typeof( school));
}
}

WPF DataBinding之我见的更多相关文章

  1. WPF QuickStart系列之数据绑定(Data Binding)

    这篇博客将展示WPF DataBinding的内容. 首先看一下WPF Data Binding的概览, Binding Source可以是任意的CLR对象,或者XML文件等,Binding Targ ...

  2. .NET: WPF DependencyProperty

    DependencyProperty and DependencyObject is the core of WPF data binding. We can use this two class t ...

  3. Data Binding in WPF

    http://msdn.microsoft.com/en-us/magazine/cc163299.aspx#S1   Data Binding in WPF John Papa Code downl ...

  4. WPF 的 ElementName 在 ContextMenu 中无法绑定成功?试试使用 x:Reference!

    在 Binding 中使用 ElementName 司空见惯,没见它出过什么事儿.不过当你预见 ContextMenu,或者类似 Grid.Row / Grid.Column 这样的属性中设置的时候, ...

  5. OpenDiscussion_DataDrivenDesign

    本文源于公司内部技术交流,如有不当之处,还请指正. Content: 1. What is Data-driven design? 2. WPF revolution. 3. More about O ...

  6. practical system design with mef & mef[ trans from arup.codeplex.com/]

    Practical System Design using MEF MVVM RX MOQ Unit Tests in WPF Posted on May 21, 2015 by Arup Baner ...

  7. Debug Databinding Issues in WPF

    DataBinding is one of the most powerful features in WPF. But because it resolves the bindings at run ...

  8. [WPF系列]-DataBinding(数据绑定) 自定义Binding

    自定义Binding A base class for custom WPF binding markup extensions BindingDecoratorBase Code: public c ...

  9. [WPF系列]-DataBinding 绑定计算表达式

            Width="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={Stat ...

随机推荐

  1. poj 2975 Nim(博弈)

    Nim Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5232   Accepted: 2444 Description N ...

  2. NOI题库05 派

    05:派 Description 我的生日要到了!根据习俗,我需要将一些派分给大家.我有N个不同口味.不同大小的派.有F个朋友会来参加我的派对,每个人会拿到一块派(必须一个派的一块,不能由几个派的小块 ...

  3. Nova 无法向虚机注入密钥

    欢迎各位关注我的博客:http://weibo.com/u/216633637 废话开头: 之前参考这位同学的博客http://www.cnblogs.com/awy-blog/p/3447176.h ...

  4. 中科院NLPIR中文分词java版

    中科院NLPIR中文分词java版 中科院NLPIR中文分词java版

  5. Nginx + Tomcat 动静分离实现负载均衡

    0.前期准备 使用Debian环境.安装Nginx(默认安装),一个web项目,安装tomcat(默认安装)等. 1.一份Nginx.conf配置文件 # 定义Nginx运行的用户 和 用户组 如果对 ...

  6. 宁波Uber优步司机奖励政策(1月25日~1月31日)

    滴快车单单2.5倍,注册地址:http://www.udache.com/ 如何注册Uber司机(全国版最新最详细注册流程)/月入2万/不用抢单:http://www.cnblogs.com/mfry ...

  7. java 打包插件

    是时候闭环Java应用了 原创 2016-08-16 张开涛  你曾经因为部署/上线而痛苦吗?你曾经因为要去运维那改配置而烦恼吗?在我接触过的一些部署/上线方式中,曾碰到过以下一些问题: 1.程序代码 ...

  8. oracle REPLACE 函数 介绍

    oracle REPLACE 函数是用另外一个值来替代串中的某个值. 例如,可以用一个匹配数字来替代字母的每一次出现.REPLACE 的格式如下所示: REPLACE ( char, search_s ...

  9. uva11549 Floyd判圈法

    题意: 给两个数n, k,每次将k平方取k的前n位,问所有出现过的数的最大值 原来这就是floyd判圈法.. #include<cstdio> #include<cstdlib> ...

  10. hibernate之自定义持久化实现