数据绑定并不是Win10的新东西,早在WP7/Win8时代就有了。但是在Win10有新的特性与改变,这在文章的后面讲解。
下面通过几个简单实例说明几种常用的绑定用法。
1、ElementName的使用:
目标:通过Slider的Value值控制Rectangle的Width属性值
实现:
<Slider x:Name="slider" Minimum="0" Maximum="500" StepFrequency="1"/>
<Rectangle Width="{Binding Value, ElementName=slider}" Height="10" Fill="Blue"/>
目标:通过Slider的Value值控制TextBox的Text属性值
实现:
<Slider x:Name="slider" Minimum="0" Maximum="500" StepFrequency="1"/>
<TextBox Text="{Binding Value, ElementName=slider}" />
2、绑定方式 Mode
上面的例子中通过滑动Slider可以控制TextBox的Text属性,但是却不能改变TextBox的Text值改变Slider的位置。
这时候需要改变Mode的值:
<TextBox Text="{Binding Value, ElementName=slider, Mode=TwoWay}" />
此时当TextBox失去焦点时,Slider的值将跟着变化
Mode的取值可以是OneTime、OneWay和TwoWay,如果不写的话默认值是OneWay
OneTime :仅当应用程序启动时或 DataContext 进行更改时更新目标属性
OneWay:源更新时,目标也更新
TwoWay:源更新时目标也更新,或者目标更新时同时更新源
3、Converter和ConverterParameter
前提:能获取到的是值是某个String值
目标:需要显示一个新的String值的,新的String值是通过修改原始String值得到的
实现:
XAML:
<TextBox x:Name="textBox" Text="apple is good!"/>
<TextBlock Text="{Binding ElementName=textBox, Path=Text,Converter={StaticResource String2NewStringConverter},ConverterParameter=cherish}"/>
其中ConverterParameter是可选的,就是传递给转换器的参数值
String2NewStringConverter是一个资源,在页面中定义:
<Page.Resources>
<local:StringToNewStringConverter x:Key="String2NewStringConverter" />
</Page.Resources>
StringToNewStringConverter是一个实现了IValueConverter接口的类,一般习惯将类名命名为"***Converter":
IValueConverter接口要求实现两个函数,Convert和ConvertBack
StringToNewStringConverter的实现:
public class StringToNewStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return string.Format("hello windows 10:\nOld String:{0}\nNew String:{1}\nby {2}",value,value.ToString().Replace("apple","microsoft"),parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}
效果图:
4、INotifyPropertyChanged和INotifyCollectionChanged
通过下面的示例可以简单实现集合类数据的绑定。
XAML:
<ListView x:Name="listView" Grid.Row="0">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="{Binding Symbol}"/>
<TextBlock Text="{Binding Label}" Margin="24,0,0,0" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
C#:
public sealed partial class MainPage : Page
{
private List<NavLink> navLinks = new List<NavLink>()
{
new NavLink() { Label = "People", Symbol = Symbol.People },
new NavLink() { Label = "Globe", Symbol = Symbol.Globe },
new NavLink() { Label = "Message", Symbol = Symbol.Message },
new NavLink() { Label = "Mail", Symbol = Symbol.Mail },
new NavLink() { Label = "CellPhone", Symbol = Symbol.CellPhone },
};
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
listView.ItemsSource = navLinks;
base.OnNavigatedTo(e);
}
}
public class NavLink
{
public string Label { get; set; }
public Symbol Symbol { get; set; }
}
效果图:
先在有一个需求:通过一个删除按钮实现对页面元素的删除
<Button Content="删除" Grid.Row="1" VerticalAlignment="Bottom" Width="100" Click="Delete_Click"/>
private void Delete_Click(object sender, RoutedEventArgs e)
{
navLinks.RemoveAt(0);
}
增加上面的代码后,点击Button发现页面并没有任何改变。那是因为navLinks是一个List集合,没有实现 INotifyCollectionChanged, INotifyPropertyChanged的接口
解决方案:
将List换成ObservableCollection。因为ObservableCollection实现上面的接口,可以简单的理解为ObservableCollection是实现了 INotifyCollectionChanged, INotifyPropertyChanged接口的List。
结论:
如果工程中自定义的类想要实现属性的改变能让UI界面获得通知,只要实现INotifyPropertyChanged接口即可,自定义的集合类需要实现INotifyCollectionChanged接口。
下面是华丽的分割线:
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
接下来的内容是Win10的新特性x:Bind
简单说,x:Bind是x:Binding一定程度上的替代品,据说是80%-90%的情况都可以替代。原来的x:Binding是运行时绑定,而x:Bind是编译时绑定。微软官方的意思就是x:Bind效率高,速度快,方便调试。两个字:好用!
1、x:Bind最重要的一个特点就是强类型
使用x:Binding时是不用考虑数据类型的,错了编译器也不会告诉你。没错有时候App莫名其妙的闪退就是它的锅!(其实是你的锅23333)
当使用x:Bind时,如果类型不匹配编译时,就会出错。
2、x:Bind默认的DataContext就是Code-Behind
所以无需我们设置上下文:"The data context of x:Bind is the code-behind class"
XAML:
<TextBlock Text="{x:Bind Text}"/>
C#:
public string Text { get; set; } = "cherish";
3、x:DataType
在使用x:Bind+DataTemplate时,必须指定x:DataType,否则编译不成功
一个简单的实例:
XAML:
<ContentControl ContentTemplate="{StaticResource MyDataTemplate}" Content="{x:Bind ViewModel}" />
其中MyDataTemplate是一个模板:
<Page.Resources>
<DataTemplate x:Key="MyDataTemplate"
x:DataType="local:MainViewModel">
<StackPanel Orientation="Horizontal">
<SymbolIcon Symbol="{x:Bind Symbol}"/>
<TextBlock Text="{x:Bind Label}" Margin="24,0,0,0" VerticalAlignment="Center"/>
</StackPanel>
</DataTemplate>
</Page.Resources>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
public MainViewModel ViewModel { get; set; } = new MainViewModel();
}
public class MainViewModel
{
public string Label { get; set; } = "People";
public Symbol Symbol { get; set; } = Symbol.People;
}
4、x:Bind默认Mode为OneTime
当绑定的数据项在后台代码中发生改变时,必须调用Bindings.Update()方法进行对UI数据的更新。
5、x:Bind绑定事件
XAML:
<Button x:Name="button" Click="{x:Bind Button_Click}"/>
C#:
public void Button_Click()
{
button.Content = "ButtonClick";
}
6、Bindings.StopTracking() 用于中断绑定
7、x:Bing与ElementName
x:Bing与ElementName不能共存,下面用x:Bind实现1中的“通过Slider的Value值控制Rectangle的Width属性值”
XAML:
<Slider x:Name="slider" Minimum="0" Maximum="500" StepFrequency="1"/>
<Rectangle Width="{x:Bind slider.Value,Mode=OneWay}" Height="10" Fill="Blue"/>
看出来了吗,这里必须指明Mode=OneWay,因为默认的Mode=OneTime
当然也可以给Slider控件添加ValueChanged事件来实现:
private void slider_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
{
Bindings.Update();
}
没错,看起来似乎变麻烦了。 但是性能得到了提升,这种小例子是看不出什么区别的。性能与便捷性通常是不能兼得的。
8、绑定与MVVM
待续...