讲讲Windows10(UWP)下的Binding

前言

貌似最近来问我XAML这块的东西的人挺多的。有时候看他们写XAML这块觉着也挺吃力的,所谓基础不牢,地动山摇。XAML这块虽说和HTML一样属于标记语言,但是世界观相对更加庞大一点。

今天讲讲XAML中的Binding。没啥技术含量,全当是快速阅读。

Binding作为MVVM模式的一个相对核心的功能,一直是有争议的。使用数据绑定可以将我们的View和Model解耦,但是如果一旦出现Bug,我们将很难调试,还有一个问题就是数据绑定会带来过大的内存开销。
跟多数的技术一样,都有自己的两面性,具体运用场景如何抉择,应该充分考虑。

作为XAML的一部分,Binding的功能也随着XAML版本的变更着。目前为止,XAML一共有以下几个版本:

  • WPF Version
  • Silverlight 3 Version
  • Silverlight 4 Version
  • Windows 8 XAML/Jupiter(Windows Runtime XAML Framework) Version

其中WPF版本的Binding功能最强大,但也开销最大。本文中,我们主要讲述最新版本,即Windows 8 XAML/Jupiter这个版本的XAML中的Binding。

开始之前

要想讲明白Binding这个东西,我们先要从Binding类的继承层次开始讲。

public class Binding : BindingBase, IBinding, IBinding2
{
    public Binding();

    public IValueConverter Converter { get; set; }
    public System.String ConverterLanguage { get; set; }
    public System.Object ConverterParameter { get; set; }
    public System.String ElementName { get; set; }
    public BindingMode Mode { get; set; }
    public PropertyPath Path { get; set; }
    public RelativeSource RelativeSource { get; set; }
    public System.Object Source { get; set; }
    
    public System.Object FallbackValue { get; set; }   
    public System.Object TargetNullValue { get; set; }
    public UpdateSourceTrigger UpdateSourceTrigger { get; set; }
}

可以看到Binding继承了BindingBase类,还继承了IBinding,IBinding2的接口。我们再分别看下这三个类和接口。首先看下我们的BindingBase。

public class BindingBase : DependencyObject, IBindingBase
{
    public BindingBase();
}

BindingBase又继承了DependencyObject和IBindingBase。DependencyObject这个我们就不多讲了,IBindingBase只是一个空接口。看来BindingBase没有看到太多信息,我们再来看下IBinding和IBinding2。

internal interface IBinding
{
    IValueConverter Converter { get; set; }
    System.String ConverterLanguage { get; set; }
    System.Object ConverterParameter { get; set; }
    System.String ElementName { get; set; }
    BindingMode Mode { get; set; }
    PropertyPath Path { get; set; }
    RelativeSource RelativeSource { get; set; }
    System.Object Source { get; set; }
}
internal interface IBinding2
{
    System.Object FallbackValue { get; set; }
    System.Object TargetNullValue { get; set; }
    UpdateSourceTrigger UpdateSourceTrigger { get; set; }
}

微软设计了一个Binding的基础模型,蕴含了接口分离原则(ISP)的思想,又提供了一个IBindingBase的空接口,如果你想实现自己的Binding模型,可以继承这个接口,这样可以和.NET类库风格统一。

讲讲IBinding

既然我们已经了解了Binding的大概的层次结构,那我们开始一个个讲讲这些都是怎么用的。

IBinding中的Path

Path是我们相对用的比较多的,多数情况下,我们可以这样写

Text="{Binding}"

XAML会取绑定源的ToString的值,所以我们可以重写Override方法来实现我们的需要的绑定。
我们也可以绑定具体的属性,比如:

Text="{Binding Name}"

如果我们绑定了一个集合,那我们也可以尝试这样写:

Text="{Binding MyList[1].Name}"

除了上述比较常用的,我们还有一个叫做ICustomPropertyProvider的接口,当你的类实现了这个接口中的

string GetStringRepresentation() 

XAML就会去取这个函数返回的值。

所以总结下我们的Path的绑定方式:

默认情况:
target Text="{Binding}"
source ToString()
//你可以重写ToString方法来改变值

属性绑定:
target Text="{Binding Name}"
source public String Name { get;}

索引器绑定:
target Text="{Binding MyList[1].Name}"

实现ICustomPropertyProvider的绑定:
target Text="{Binding}"
source String GetStringRepresentation() 
//实现方法获取值

IBinding中的Mode

Mode一共有三种,OneTime,OneWay,TwoWay。看字面的意思就很容易理解。

//OneTime
Text="{Binding, Mode=OneTime}"
//OneWay
Text="{Binding, Mode=OneWay}"
//TwoWay
Text="{Binding, Mode=TwoWay}"

在OneWay和TwoWay中,如果想要对象的值变更时让绑定目标也变化,需要注意一下两点

  • 对于普通的属性,需要类实现INotifyPropertyChanged,并且对象值变化时手动通知变更。
  • 对于依赖属性,当触发SetValue方法后,PropertyChangedCallBack会通知变更,所以无需我们手动操作。
    在UWP系统中,Mode的默认值为OneWay

IBinding中的RelativeSource

RelativeSource是一种相对关系找数据源的绑定。目前有两种:Self和TemplatedParent

//Self
<TextBlock Text="{Binding Foreground.Color.R, RelativeSource={RelativeSource Mode=Self}}" Foreground="Red"/>

//TemplatedParent
<DataTemplate> 
    <Rectangle Fill="Red" Height="30" Width="{Binding Width, RelativeSource={RelativeSource Mode=TemplatedParent}}">
</DataTemplate>  

RelativeSource绑定的方式我们常用于控件模板。默认值一般为null。

IBinding中的ElementName

ElementName也是我们最常用的一种绑定方式,使用这个我们需要注意两点:

  • 指定的ElementName必须在当前XAML名称范围里。
  • 如果绑定目标位于数据模板或控件模板中,则为模板化父级的XAML名称范围。
    举个例子:
<UserControl x:Name="Instance" Background="Red"> 
  <Grid Background="{Binding Background, ElementName=Instance}"/> 
</UserControl> 
//or
<Page x:Name="Instance"> 
  <Grid> 
    <ItemsControl ItemsSource="{Binding Users}"> 
      <ItemsControl.ItemTemplate> 
        <DataTemplate> 
          <Button Command=" {Binding DataContext.TestCommand, ElementName=Instance}"/> 
        </DataTemplate> 
      </ItemsControl.ItemTemplate> 
    </ItemsControl> 
   </Grid> 
 </Page> 

IBinding中的Source

Source也是我们常用的一种方式。

<Page> 
  <Page.Resources> 
    <SolidColorBrush x:Key="MainBrush" Color="Orange"/> 
  </Page.Resources> 
  <Grid Background="{Binding Source={StaticResource MainBrush}}"/> 
</Page>
//当然我们也可以简写为
<Grid Background="{StaticResource MainBrush}"/>

一般情况下,Source,ElementName和RelativeSource三者是互斥的,指定多余一种的绑定方式会引发异常。

IBinding中的Converter

我们很难保证我们的对象值和我们绑定目标的类型一直,所以转换器可以将类型就行转换。
使用转换器我们要实现IValueConverter接口:

public class BoolVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        bool? result = value as Nullable<bool>;
        if(result == true)
        {
            return Visibility.Visible;
        }
        return Visibility.Collapsed;

    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

如果你的值需要转换回去,你也可以继续实现ConvertBack方法。

<Page> 
  <Page.Resources> 
    <local:BoolVisibilityConverter x:Key="BoolVisibilityConverter"/> 
  </Page.Resources> 
  <Grid> 
    <Border Visibility="{Binding Busy, Converter={StaticResource BoolVisibilityConverter}}"/> 
  </Grid> 
</Page>

IBinding中的ConverterParameter和ConverterLanguage

这两个参数不能绑定,只能指定常量值。

<Border Visibility="{Binding Busy, Converter={StaticResource BoolVisibilityConverter}, 
  ConverterParameter=One, ConverterLanguage=en-US}"/> 

IBinding中的参数基本上覆盖了我们多数的需求。尽管相对于WPF缺少了多值绑定等等,但我们也能够通过自定义一些附加属性来实现这些功能。

IBinding2

IBinding2中的参数就相对使用的比较少了。

IBinding2中的FallbackValue

FallbackValue的用途是:当绑定对象不存在时,我们就使用FallbackValue的值:

<Page> 
  <Page.Resources> 
    <x:String x:Key="ErrorString">Not Found</x:String> 
  </Page.Resources> 
  <Grid> 
    <TextBlock Text="{Binding Busy, FallbackValue={StaticResource ErrorString}}"/> 
  </Grid> 
</Page>

IBinding2中的TargetNullValue

TargetNullValue的用途是:当绑定对象为空时,我们就使用TargetNullValue的值:

<Page> 
  <Page.Resources> 
    <x:String x:Key="ErrorString">Not Found</x:String> 
  </Page.Resources> 
  <Grid> 
    <TextBlock Text="{Binding Busy, TargetNullValue={StaticResource ErrorString}}"/> 
  </Grid> 
</Page>

IBinding2中的UpdateSourceTrigger

UpdateSourceTrigger的值有三种:Default,PropertyChanged,Explicit。
多数情况下大多数依赖项属性的默认值都为 PropertyChanged。但是Text属性不是。
PropertyChanged的意思是当绑定目标属性更改时,立即更新绑定源。而Explicit是只有UpdateSource方法时才更新绑定源。
举个例子:

<Grid> 
    <TextBox x:Name="TitleTextBox" Text="{Binding Title, ElementName=Instance, UpdateSourceTrigger=Explicit, Mode=TwoWay}" /> 
    <Button Click="Button_Click"/> 
</Grid>


private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    var current = this.Title; 
    TitleTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource(); 
    current = this.Title; 
}

有关uwp的Binding就说到这里。谢谢~

参考资料

被误解的MVC和被神化的MVVM
Extensible Application Markup Language
RelativeSource 标记扩展
UpdateSourceTrigger enumeration

个人推荐

我的博客园
我的简书
我的Github

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,594评论 18 139
  • 很多时候我们需要将某个View1 值的改变显示在另外一个View2 上,对View1的对应事件编码可实现我们想要的...
    MayueCif阅读 3,994评论 2 3
  • 什么是Xaml Xaml(Extensible Application Markup Language) 可扩展应...
    北风知我意阅读 643评论 0 1
  • 目录 什么是WPF? WPF的历史? 为什么要用WPF及WPF作用 WPF与winForm区别? 什么是WPF? ...
    灬52赫兹灬阅读 5,777评论 2 11
  • 近段时期,校园暴力充斥着我们的朋友圈:中关村二小被同学欺凌;山西运城少年被同学围欧致死;重庆彭水学生厕所内被同学杀...
    ef8371372682阅读 1,436评论 0 1