程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WPF學習筆記 - 8. Binding (1)

WPF學習筆記 - 8. Binding (1)

編輯:關於.NET

1. 綁定簡介

WPF 綁定可以在源數據對象和 UI 控件間建立聯系,實現單向或雙向變更通知,以此實現更好的業務邏輯和 UI 的分離。通常的模式是: 將目標對象(通常是XAML元素控件等)的目標屬性(必須是依賴屬性)通過綁定對象(Binding對象實例)綁定到數據源(CLR對象、ADO.NET 數據表、XML數據等)。比如我們可以將 TextBox1.Text 綁定到 Personal.Name。

下面的例子中,我們可以觀察到如下自動行為。

(1) 單擊 btnSet 修改源對象,會發現目標屬性 textbox1.Text 自動變更。

(2) 修改 textbox1.Text,單擊 btnGet 會發現源對象被自動修改。

Window.xaml

<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" Height="276" Width="360" WindowStartupLocation="CenterScreen">
  <Grid>
    <StackPanel>
      <TextBox x:Name="textbox1" />
      <Button x:Name="btnGet" Content="Get Name" Click="buttonClick" />
      <Button x:Name="btnSet" Content="Set Name" Click="buttonClick" />
    </StackPanel>
  </Grid>
</Window>

Windows.xaml.cs

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); }
  }
}
public partial class Window1 : Window
{
  MyData data;
  public Window1()
  {
    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 Window1 : Window
{
  Data data;
  public Window1()
  {
    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);
  }
}

好了,現在支持雙向變更自動更新了。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved