WPF 学习笔记《7》——Binding《1》

实例代码:https://files.cnblogs.com/xuwenfeng/binding1.rar

1. 绑定简介

WPF 绑定可以在源数据对象和 UI 控件间建立联系,实现单向或双向变更通知,以此实现更好的业务逻辑和 UI 的分离。通常的模式是: 将目标对象(通常是XAML元素控件等)的目标属性(必须是依赖属性)通过绑定对象(Binding对象实例)绑定到数据源(CLR对象、ADO.NET 数据表、XML数据等)。比如我们可以将 TextBox1.Text 绑定到 Personal.Name。

下面的例子中,我们可以观察到如下自动行为。

(1) 单击 btnSet 修改源对象,会发现目标属性 textbox1.Text 自动变更。
(2) 修改 textbox1.Text,单击 btnGet 会发现源对象被自动修改。

MainWindow.xmal

<Window x:Class="WpfApplication6.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>
<StackPanel>
<TextBox x:Name="textbox1" />
<Label x:Name="label1" Content="{Binding ElementName=textbox1, Path=Text}" />
<Button x:Name="btnGet" Content="Get Name" Click="buttonClick" />
<Button x:Name="btnSet" Content="Set Name" Click="buttonClick" />
</StackPanel>
</Grid>
</Window>

MainWindow.xaml

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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.Timers;

namespace WpfApplication6
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
class MyData : DependencyObject
{
public static readonly DependencyProperty NameProperty =
DependencyProperty.Register(
"Name", typeof(string), typeof(MyData),
new UIPropertyMetadata("Hello, World!"));

public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
}
MyData data;
public MainWindow()
{
InitializeComponent();
data
= new MyData();
var binding
= new Binding("Name") { Source = data };
this.textbox1.SetBinding(TextBox.TextProperty, binding);
}

private void buttonClick(object sender, RoutedEventArgs e)
{
if (sender == btnSet)
data.Name
= DateTime.Now.ToString();
else
MessageBox.Show(data.Name);
}
}
}

很显然,这种效果可以让开发人员只关注业务逻辑或者 UI 展示,大大降低了两者之间的代码关联。

我们还可以使用 Binding.Mode 属性来指定绑定变更通知的方向,默认情况下通常是双向绑定。

OneWay: 对数据源进行修改,会自动更新目标属性。而对目标属性的修改则不会影响源对象。
TwoWay: 无论是修改数据源还是目标属性,都会自动更新另一方。
OneWayToSource: 和 OneWay 相反,当修改目标属性时会自动更新数据源,反之则不然。
OneTime: 仅在初始化时修改目标属性。

data = new MyData();
var binding = new Binding("Name") { Source = data, Mode = BindingMode.OneWay };
this.textbox1.SetBinding(TextBox.TextProperty, binding);

System.Windows.Data.BindingOperations 类提供了绑定所需的全部的操作方法。和 FrameworkElement.SetBinding() 相比,BindingOperations.SetBinding 方法可能更通用些,因为它可以直接使用 DependencyObject 对象。

public BindingExpression FrameworkElement.SetBinding(DependencyProperty dp, BindingBase binding)

public static BindingExpressionBase BindingOperations.SetBinding(DependencyObject target, DependencyProperty dp, BindingBase binding)

将上面例子改成 BindingOperations 试试。

BindingOperations.SetBinding(this.textbox1, TextBox.TextProperty, new Binding("Name") { Source = data });

我们可以用 ClearBinding 方法解除绑定。

private void buttonClick(object sender, RoutedEventArgs e)
{
if (sender == btnSet)
data.Name
= DateTime.Now.ToString();
else if (sender == btnClear)
BindingOperations.ClearBinding(
this.textbox1, TextBox.TextProperty);
else
MessageBox.Show(data.Name);
}

单击 btnClear 后,你会发现绑定自动变更失效。

2. 在 XAML 中使用绑定

在 XAML 中我们不能使用 SetBinding,而必须改用扩展标记 Binding (注意没有 Extension 后缀)。该扩展标记可将目标属性绑定到静态资源(StaticResource)或者其他XAML元素(包括目标元素自身)上。

 

(1) 绑定到其他元素

<Window x:Class="Learn.WPF.Window1"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
Title
="Window1">
<Grid>
<StackPanel>
<TextBox x:Name="textbox1" />
<Label x:Name="label1" Content="{Binding ElementName=textbox1, Path=Text}" />
</StackPanel>
</Grid>
</Window>

(2) 绑定到静态资源

<Window x:Class="Learn.WPF.Window1"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
Title
="Window1">
<Window.Resources>
<ContentControl x:Key="text">Hello, World!</ContentControl>
</Window.Resources>
<Grid>
<StackPanel>
<Label x:Name="label1" Content="{Binding Source={StaticResource text}}" />
</StackPanel>
</Grid>
</Window>

System.Windows.Data.Binding.Source 并不是一个依赖属性,因此我们无法将其绑定到一个动态资源(DynamicResouce)上。

 

(3) 绑定到自身

<Window x:Class="Learn.WPF.Window1"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
Title
="Window1">
<Grid>
<StackPanel>
<Label x:Name="label1" Content="{Binding RelativeSource={RelativeSource Self}, Path=Name}" />
</StackPanel>
</Grid>
</Window>

(4) 绑定到指定类型的父元素

<Window x:Class="Learn.WPF.Window1"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
Title
="Window1">
<Grid x:Name="Grid1">
<StackPanel>
<Label x:Name="label1" Content="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Grid}}, Path=Name}" />
</StackPanel>
</Grid>
</Window>

3. 绑定到普通对象

WPF 允许将任何 .NET 对象作为数据绑定源。

class Data
{
public string Name { get; set; }
}

public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();

var data
= new Data { Name = "Q.yuhen" };
BindingOperations.SetBinding(
this.textbox1, TextBox.TextProperty, new Binding("Name") { Source = data });
}
}

不过有个问题,就是当我们修改数据源时,目标属性会因为无法接收变更通知而自动更新。要解决这个问题,我们需要让数据源对象实现 System.ComponentModel.INotifyPropertyChanged 接口。

public delegate void PropertyChangedEventHandler(object sender, PropertyChangedEventArgs e);

public interface INotifyPropertyChanged
{
// Events
event PropertyChangedEventHandler PropertyChanged;
}

我们试着修改一下上面例子中的 Data 类型。

class Data : INotifyPropertyChanged
{
private string name;
public event PropertyChangedEventHandler PropertyChanged;

public string Name
{
get
{
return name;
}
set
{
if (value != name)
{
name
= value;

if (PropertyChanged != null)
{
PropertyChanged(
this, new PropertyChangedEventArgs("Name"));
}
}
}
}
}

public partial class MainWindow : Window
{
Data data;

public MainWindow()
{
InitializeComponent();

data
= new Data { Name = "Q.yuhen" };
BindingOperations.SetBinding(
this.textbox1, TextBox.TextProperty,
new Binding("Name") { Source = data });
}

protected void ButtonClick(object sender, RoutedEventArgs e)
{
if (sender == button1)
data.Name
= DateTime.Now.ToString();
else
MessageBox.Show(data.Name);
}
}

posted @ 2011-08-18 13:13  徐文峰  阅读(527)  评论(0)    收藏  举报