Binding(一)——Binding基础

一、Binding概述

Binding注重表达它是一种像桥梁一样的关联关系。WPF中,正是在这段桥梁上我们有机会为往来流通的数据做很多事情。

如果把Binding比作数据的桥梁,那么它的两端分别是Binding的源(Source)和目标(Target)。数据从哪里来哪里就是源,Binding是中间的桥梁,目标是数据要往哪里去。一般情况下,Binding源是逻辑层的对象,Binding目标是UI层的控制对象。这样,数据就会源源不断通过Binding送达UI层,也就完成了数据驱动UI的过程。想象Binding是在桥梁上铺设了高速公路,我们不但可以控制双向通行还是某个方向的单行道,还可以控制对数据放行的时机,甚至可以在桥上架设一些“关卡”用来转换数据类型或验证数据的正确性。

让我们来看一个最简单的例子。创建一个简单的数据源并通过Binding把它连接到UI元素上。

首先,创建Student类,这个类的实例将作为数据源来使用。

    public class Student
    {
        private string name;

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }


前面说过,数据源是一个对象,一个对象身上可能有很多数据,这些数据通过属性暴露给外界。那么,其中的哪些数据是想通过Binding送达到UI层呢?UI上的元素关心的是哪些属性值的变化呢?这个属性就称为Binding的路径(Path)。但光有属性还不够——Binding是一种自动机制,当数值变化后要有能力通知Binding。方法是在属性的set语句中激发一个PropertyChanged事件。这个事件不需要自己声明,只需要让作为数据源的类实现INotifyPropertyChanged接口。

当为Binding设置了数据源后,Binding就会自动侦听来自这个接口的PropertyChanged事件。修改Student类。

    public class Student:INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private string name;

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

经过修改后,当Name属性的值发生变化时,PropertyChanged事件就会被激发。Binding接受到这个事件后发现事件告诉它是名为Name的属性发生了改变,于是就会Binding目标端的UI元素显示新的值。

前端代码如下。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Simple Binding" Height="110" Width="300">
    <StackPanel>
        <TextBox x:Name="textBoxName" BorderBrush="Black" Margin="5"/>
        <Button Content="Add Age" Margin="5" Click="Button_Click"/>
    </StackPanel>
</Window>

接下来,最重要的一步,使用Binding把数据源和UI元素连接起来。

    public partial class MainWindow : Window
    {
        Student stu;

        public MainWindow()
        {
            InitializeComponent();

            Student stu = new Student();

            Binding binding = new Binding();
            binding.Source = stu;
            binding.Path = new PropertyPath("Name");

            BindingOperations.SetBinding(this.textBoxName, TextBox.PaddingProperty, binding);
        }

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

在准备Binding的部分,先是用Binding binding = new Binding(); 声明Binding类型变量并创建实例;然后使用bingding.Source = stu;为Binding实例指定数据源;最后使用binding.Path =  new PropertyPath("Name");为Binding指定访问路径。

把数据源和目标连接在一起的任务是使用BindingOperations.SetBinding(...);方法来完成的。

  • 第一个参数用于指定Binding的目标。
  • 第二个参数用于为Binding指明把数据送达目标的哪个属性。这里使用的不是对象的属性而是类的一个静态只读的依赖属性。
  • 第三个参数指定使用哪个Binding实例讲数据源与目标关联。

实际工作中,代码可能不一样。原因是TextBox这类UI元素的基类FrameworkElement对BindingOperations.SetBinding(...)方法进行了封装。

        public BindingExpressionBase SetBinding(DependencyProperty dp, BindingBase binding)
        {
            return BindingOperations.SetBinding(this, dp, binding);
        }

可以借助类的构造器和对象化初始化器来简化代码。

    public partial class MainWindow : Window
    {
        Student stu;

        public MainWindow()
        {
            InitializeComponent();

            this.textBoxName.SetBinding(TextBox.TextProperty, new Binding("Name") { Source = stu = new Student() });
        }

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

二、把控件作为Binding源与Binding标记扩展

大多数情况下Binding的源是逻辑层的对象,但有时候为了让UI元素产生一些联动效果也会使用Binding在控件之间建立关联。下面的代码是把一个TextBox的Texts属性关联在Slider的Value属性上。

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Control as Source" Height="110" Width="300">
    <StackPanel>
        <TextBox x:Name="textBox1" Text="{Binding Path=Value, ElementName=slider1}" BorderBrush="Black" Margin="5"/>
        <Slider x:Name="slider1" Maximum="100" Minimum="0" Margin="5"/>
    </StackPanel>
</Window>

如大家所见,除了可以在C#中利用PropertyChanged建立Binding外。在XAML代码里也可以方便地设置Binding。值得注意的是,在C#代码中可以访问XAML代码中声明的变量但XAML代码中却无法访问C#代码中声明的变量。

来看一下这句XAML代码,它使用了Binding标记扩展语法:

<TextBox x:Name="textBox1" Text="{Binding Path=Value, ElementName=slider1}" BorderBrush="Black" Margin="5"/>

与之等价的C#代码是:

this.textBox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = "slider1" });

由于Binding类的构造器本省可以接受Path作为参数,所以也经常写为:

<TextBox x:Name="textBox1" Text="{Binding Value, ElementName=slider1}" BorderBrush="Black" Margin="5"/>

三、控制Binding的方向及数据更新

默认情况下数据既能够通过Binding送达目标,也能够从目标返回源。有时候数据只需要展示给用户、不允许用户修改,这时可以把Binding模式更改为从源向目标的单向流通。除此以外Binding还支持其他很多的流通模式,这需要根据实际情况去选择。

控制Binding数据流向的属性是Mode,它的类型是BindingMode枚举。BindingMode可取值是TwoWay、OneWay、OnTime、OneWayToSource和Default。这里的Default值并不固定,它会根据指定目标的实际情况来确定。比如若是可编辑的TextBox.Text属性,,Default就采用双向模式;若是只读的TextBlock.Text属性,则采用单向模式。

在上个例子中,拖动Slider手柄时,TextBox里就会显示Slider当前的Value;如果在TextBox里输入一个恰当的值,然后按下Tab让焦点离开TextBox,则Slider的手柄会跳到相应的位置。

为什么一定要在TextBox失去焦点之后Slider的值才会改变?这就引出了Binding的另一个属性UpdateSourceTrigger,它的类型是UpdateSourceTrigger枚举,可取PropertyChanged、LostFocus、Explicit和Default。同样地,对于TextBox默认值的行为与LostFocus一致。我们只需把这个属性改为PropertyChanged,则Slider的手柄就会随着我们在TextBox里的输入改变而改变位置。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在GroovyBinding是一个非常重要的类,它允许我们在运行时动态地创建变量和方法,并将它们绑定到一个特定的上下文。这个上下文可以是一个Groovy脚本、一个Groovy类或一个Java类。 在实际开发,我们通常需要在多个Groovy脚本之间共享一些代码或变量。这时,我们可以使用Binding来实现共享。具体来说,我们可以在一个Groovy脚本创建一个Binding对象,并将需要共享的变量绑定到这个对象。然后,在其他Groovy脚本,我们可以通过访问这个Binding对象来获取这些共享的变量。 举个例子,假设我们有两个Groovy脚本A.groovy和B.groovy,它们都需要使用同一个变量greeting。我们可以在A.groovy创建一个Binding对象,并将greeting绑定到这个对象: ``` def binding = new Binding() binding.setVariable("greeting", "Hello, world!") ``` 然后,在B.groovy,我们可以通过访问这个Binding对象来获取greeting变量: ``` def binding = new Binding() def greeting = binding.getVariable("greeting") println greeting ``` 这样,我们就可以在不同的Groovy脚本之间共享变量了。 除了变量,我们还可以通过Binding共享方法。具体来说,我们可以在一个Groovy脚本定义一个方法,并将它绑定到一个Binding对象。然后,在其他Groovy脚本,我们可以通过访问这个Binding对象来调用这个方法。 举个例子,假设我们有两个Groovy脚本A.groovy和B.groovy,它们都需要使用同一个方法sayHello。我们可以在A.groovy定义这个方法,并将它绑定到一个Binding对象: ``` def sayHello(name) { println "Hello, $name!" } def binding = new Binding() binding.setVariable("sayHello", &sayHello) ``` 然后,在B.groovy,我们可以通过访问这个Binding对象来调用sayHello方法: ``` def binding = new Binding() def sayHello = binding.getVariable("sayHello") sayHello("world") ``` 这样,我们就可以在不同的Groovy脚本之间共享方法了。 综上所述,通过Binding,我们可以在不同的Groovy脚本之间共享变量和方法。这种方式非常灵活,也非常适合一些需要共享代码的场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值