讲讲Windows10(UWP)下的Binding

前言

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

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

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

做为XAML的一部分,Binding的功能也随着XAML版本的变动着。目前为止,XAML一共有如下几个版本:mvc

  • 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。app

开始以前

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

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。ide

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类库风格统一。ui

讲讲IBinding

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

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

相关文章
相关标签/搜索