WPF Binding基礎


  如果把Binding比作數據的橋梁,那么它的兩端分別是Binding的源和目標。數據從哪里來就是源,Binding是架在中間的橋梁,Binding目標是數據要往哪兒去。一般情況下,Binding源是邏輯層的對象,Binding目標是UI層的控件對象,這樣,數據就會源源不斷通過Binding送達UI層,被UI層展現,也就完成了數據驅動UI的過程。

  數據源是一個對象,一個對象上可能有很多數據,這些數據又通過屬性暴露給外界。那么,其中哪個數據是你想通過Binding送達UI的元素呢?換句話說,UI上的元素關心的是哪個屬性值的變化,這個屬性就稱為Binding的路徑(Path)。但光有屬性還不行----Binding是一種自動機制,當值變化后屬性要有能力通知Binding,讓Binding把變化傳遞給UI元素。怎樣才能讓一個屬性具備這種通知Binding值已經變化的能力呢?方法就是在set語句中激發一個PropertyChanged事件。這個事件不需要我們自己聲明,我們要做的是讓作為數據源的類實現INotifyPropertyChanged接口。當Binding設置了數據源之后,Binding就會自動偵聽來自這個接口的PropertyChanged事件。

<StackPanel>
        <TextBox x:Name="txtName" BorderBrush="Black" Margin="5"></TextBox>
        <Button Content="AddAge" Margin="5" Click="Button_Click"></Button>
    </StackPanel>

 

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

        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
                }
            }
        }

    }
public partial class MainWindow : Window
    {
        Student stu;
        public MainWindow()
        {
            InitializeComponent();
            stu = new Student();
            //准備Binding
            Binding binding = new Binding();
            binding.Source = stu;
            binding.Path = new PropertyPath("Name");
            //使用Binding,連接數據源和Binding目標
            BindingOperations.SetBinding(this.txtName, TextBox.TextProperty, binding);
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            stu.Name += "Name";
        }
    }

這樣,當點擊button的時候,改變了stu對象的Name屬性,該數據會自動更新到UI,就是TextBox

原理大致如此,寫法卻有很多,比如BindingOperations.SetBinding,繼承自FrameworkElement的類都封裝了該方法

public BindingExpression SetBinding(DependencyProperty dp, string path);

所以還可以這樣寫

InitializeComponent();
            stu = new Student();
            //准備Binding
            Binding binding = new Binding();
            binding.Source = stu;
            binding.Path = new PropertyPath("Name");
            //使用Binding,連接數據源和Binding目標
            //BindingOperations.SetBinding(this.txtName, TextBox.TextProperty, binding);
            txtName.SetBinding(TextBox.TextProperty, binding);

既然Binding作為源和目標間數據的橋梁,那么數據也是有方向的,控制Binding數據流向的屬性是Mode

public enum BindingMode
    {
        // 摘要:
        //     導致對源屬性或目標屬性的更改可自動更新對方。此綁定類型適用於可編輯窗體或其他完全交互式 UI 方案。
        TwoWay = 0,
        //
        // 摘要:
        //     當綁定源(源)更改時,更新綁定目標(目標)屬性。如果要綁定的控件為隱式只讀控件,則適用此綁定類型。例如,可以綁定到如股市代號之類的源。或者,可能目標屬性沒有用於進行更改(例如表的數據綁定背景色)的控件接口。如果不需要監視目標屬性的更改,則使用
        //     System.Windows.Data.BindingMode.OneWay 綁定模式可避免 System.Windows.Data.BindingMode.TwoWay
        //     綁定模式的系統開銷。
        OneWay = 1,
        //
        // 摘要:
        //     當應用程序啟動或數據上下文更改時,更新綁定目標。此綁定類型適用於以下情況:使用當前狀態的快照適合使用的或數據狀態實際為靜態的數據。如果要從源屬性初始化具有某個值的目標屬性,並且事先不知道數據上下文,則也可以使用此綁定類型。實質上,這是
        //     System.Windows.Data.BindingMode.OneWay 綁定的較簡單的形式,它在不更改源值的情況下可提供更好的性能。
        OneTime = 2,
        //
        // 摘要:
        //     當目標屬性更改時更新源屬性。
        OneWayToSource = 3,
        //
        // 摘要:
        //     使用綁定目標的默認 System.Windows.Data.Binding.Mode 值。每個依賴項屬性的默認值都不同。一般情況下,用戶可編輯控件屬性(例如文本框和復選框的屬性)默認為雙向綁定,而多數其他屬性默認為單向綁定。確定依賴項屬性綁定在默認情況下是單向還是雙向的編程方法是:使用
        //     System.Windows.DependencyProperty.GetMetadata(System.Type) 來獲取屬性的屬性元數據,然后檢查
        //     System.Windows.FrameworkPropertyMetadata.BindsTwoWayByDefault 屬性的布爾值。
        Default = 4,
    }

Binding還有另外一個屬性來控制何時更新數據,它是UpdateSourceTrigger

public enum UpdateSourceTrigger
    {
        // 摘要:
        //     綁定目標屬性的默認 System.Windows.Data.UpdateSourceTrigger 值。多數依賴項屬性的默認值為 System.Windows.Data.UpdateSourceTrigger.PropertyChanged,而
        //     System.Windows.Controls.TextBox.Text 屬性的默認值為 System.Windows.Data.UpdateSourceTrigger.LostFocus。
        Default = 0,
        //
        // 摘要:
        //     當綁定目標屬性更改時,立即更新綁定源。
        PropertyChanged = 1,
        //
        // 摘要:
        //     當綁定目標元素失去焦點時,更新綁定源。
        LostFocus = 2,
        //
        // 摘要:
        //     僅在調用 System.Windows.Data.BindingExpression.UpdateSource() 方法時更新綁定源。
        Explicit = 3,
    }

順便提一句,Binding還有具有NotifyOnSourceUpdate和NotifyOnTargetUpdate兩個bool類型的屬性,如果設置為true,則當源或目標被更新后Binding會被激發相應的SourceUpdated事件和TargetUpdated事件。實際工作中,我們可以通過監聽兩個事件來找出有哪些數據或控件被更新了。

 

沒有Source的Binding——使用DataContext作為Binding的源

首先創建一個數據源類

public class Student
    {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Age { get; set; }
    }
<Window x:Class="BindingSample2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BindingSample2"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <StackPanel.DataContext>
            <local:Student Age="22" Name="HuangTao" Id="Hello"></local:Student>
        </StackPanel.DataContext>
        <Grid>
            <StackPanel>
                <TextBox Text="{Binding Path=Id}" Margin="5"></TextBox>
                <TextBox Text="{Binding Path=Name}" Margin="5"></TextBox>
                <TextBox Text="{Binding Path=Age}" Margin="5"></TextBox>
            </StackPanel>
        </Grid>
    </StackPanel>
</Window>

這3個TextBox的Binding就會自動向UI元素樹的上層去尋找可用的DataContext對象。

沒有Source沒有Path的Binding,但源本身就是數據的時候

<Window x:Class="BindingSample2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BindingSample2"
        xmlns:sys="clr-namespace:System;assembly=mscorlib"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <StackPanel.DataContext>
            <!--<local:Student Age="22" Name="HuangTao" Id="Hello"></local:Student>-->
            <sys:String>Hello!</sys:String>
        </StackPanel.DataContext>
        <Grid>
            <StackPanel>
                <!--<TextBox Text="{Binding Path=Id}" Margin="5"></TextBox>
                <TextBox Text="{Binding Path=Name}" Margin="5"></TextBox>
                <TextBox Text="{Binding Path=Age}" Margin="5"></TextBox>-->
                <TextBlock Text="{Binding}" Margin="5"></TextBlock>
            </StackPanel>
        </Grid>
    </StackPanel>
</Window>

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM