原创,转载请注明出处: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. luoguP2267 琪琪的项链

    题目:http://www.luogu.org/problem/show?pid=2267 题解:这题略吊. 看了之后发现不能用组合数学直接得出公式,然后如果直接暴力也不知道如何去排除两个颜色序列相同 ...

  2. position: absolute 的元素自动对齐父元素 border 外边缘

    Position with border outer edge CSS box-flex align-items justify-content

  3. 【EJS】

    // 用=号输出,就会被escapge转义编码 <%= VARIABLE_NAME %> // 用“-”输出原始内容, 不会被escape <%- VARIABLE_NAME %&g ...

  4. Linux Shell编程(13)——数字常量

    除非一个数字有特别的前缀或符号,否则shell脚本把它当成十进制的数.一个前缀为0的数字是八进制数.一个前缀为0x的数字是十六进制数.一个数用内嵌的#来求值则看成BASE#NUMBER(有范围和符号限 ...

  5. (转载)MySQL默认INFORMATION_SCHEMA,MySQL,TEST三个数据库用途

    (转载)http://www.45it.com/database/201204/29390.htm 本文简要说明了MySQL数据库安装好后自带的INFORMATION_SCHEMA,MySQL,TES ...

  6. js弹框处理

    # -*- coding:utf-8 -*- """ js弹框处理 """ from selenium import webdriver d ...

  7. 解压华为P6 UPDATE.APP

    #!/usr/bin/env python # Version: 0.2.201308040830 # Author: linkscue # Function: unpack any hauwei h ...

  8. Java Bean 获取properties文件的读取

    实际的开发过程中,将一些配置属性从java代码中提取到properties文件中是个很好的选择,降低了代码的耦合度.下面介绍两种通过spring读取properties文件的方法,以ip地址配置为例. ...

  9. C# SQL 整表插入 分类: C# 2014-09-17 16:18 369人阅读 评论(2) 收藏

    说明: (1)表A的一部分数据插入到表B (2)DataAccess 类,是放在DAL层下的底层类; da.StrConnection 写在DataAccess类中; //整表插入方法 private ...

  10. Windows Media Player axWindowsMediaPlayer1 分类: C# 2014-07-28 12:04 195人阅读 评论(0) 收藏

    属性/方法名: 说明: [基本属性] URL:String; 指定媒体位置,本机或网络地址 uiMode:String; 播放器界面模式,可为Full, Mini, None, Invisible p ...