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>

 

 

 

 

posted @ 2013-02-08 12:01  UncleNull  阅读(3829)  评论(4编辑  收藏  举报