功能简介
示例项目有个一页面MainPage,实现MainPage里的数据双向绑定到界面(ListView)上,在界面的操作对数据模型的修改能实时反映到数据;而数据的变更能实时展现到界面。
实现效果
- Array到ListView的数据绑定
- ListView到Array的绑定
实现过程
新建一个类Item.cs
//Item.cs
namespace TwoWayDataBinding
{
/*
* Item是我们自定义的一个类型,包含三个属性,对应三个控件的属性
* Content --> 文本框的内容
* Source --> Image的Source
* Ischecked --> Checkbox的checked
* 这里继承了接口INotifyPropertyChanged,当客户端某一属性值发生更改时,发出通知
*/
public class Item : INotifyPropertyChanged
{
private string _content;
private string _source;
private bool _ischecked;
public string Content {
get => _content;
set { _content = value; OnPropertyChanged("Content") ; }
}
public string Source {
get => _source;
set { _source = value; OnPropertyChanged("Source"); }
}
public bool Ischecked {
get => _ischecked;
set { _ischecked = value; OnPropertyChanged("Ischecked"); }
}
public Item(string content, string source, bool ischecked)
{
this._content = content;
this._source = source;
this._ischecked = ischecked;
}
//显示实现接口,实现数据绑定动态更新
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName = "")
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
需要注意的地方:
- 与上一篇博客相比,对Item类的每一个属性添加了set方法,因为对ListView的修改将导致Item的实时更新,所以需要set方法
- 继承接口INotifyPropertyChanged
- set方法中的OnPropertyChanged函数,是为了发送通知,实现数据绑定动态更新
新建一个类CheckBoxConverter作为转换器
//CheckBoxConverter.cs
namespace TwoWayDataBinding
{
/*
* 转化器,将布尔值转化为Checkbox的IsChecked属性
*/
public class CheckBoxConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
bool? isChecked = value as bool?;
if (isChecked == null || isChecked == false)
{
return false;
}
else
{
return true;
}
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
bool? isChecked = value as bool?;
if (isChecked == null || isChecked == false)
{
return false;
}
else
{
return true;
}
}
}
}
关于转换器可以看上一篇博客
在MainPage.xaml中添加控件和声明资源文件
<!-- MainPage.xaml -->
<!-- 声明资源文件 -->
<Page.Resources>
<local:CheckBoxConverter x:Key="ConvertCheck"></local:CheckBoxConverter>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<!-- ItemSource用于指定ListView的数据源 -->
<ListView Margin="20,20,50,20" ItemsSource="{x:Bind Array}">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Item">
<RelativePanel>
<!-- Source="{x:Bind Ischecked}"指定CheckBox是否被选中 -->
<CheckBox IsChecked="{x:Bind Ischecked,Converter={StaticResource ConvertCheck},Mode=TwoWay}" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10,10,0,0"></CheckBox>
<Grid Width="90" x:Name="Space"></Grid>
<!-- Source="{x:Bind Source}"指定Image图片控件的图片源 -->
<Image Source="{x:Bind Source,Mode=OneWay}" HorizontalAlignment="Left" Height="40" Margin="50,10,0,0" VerticalAlignment="Top" Width="40"></Image>
<!-- Text="{x:Bind Content}"指定文本块的内容,Source和Content都是Item的属性 -->
<TextBox Text="{x:Bind Content,Mode=TwoWay}" RelativePanel.RightOf="Space" VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="20" Margin="10,12,0,0"></TextBox>
</RelativePanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
<!--
点击Add按钮将往Array中添加元素
点击ShowResults按钮将打印Array的内容
-->
<Page.BottomAppBar>
<CommandBar>
<AppBarButton Icon="Add" Click="AddButton_Click"/>
<AppBarButton Icon="ShowResults" Click="ShowButton_Click"/>
</CommandBar>
</Page.BottomAppBar>
需要注意的地方:
- 和之前的示例相比,数据绑定的Mode由OneWay变为了TwoWay
在MainPage.cs文件中添加代码
//MainPage.cs
namespace TwoWayDataBinding
{
public sealed partial class MainPage : Page
{
//用于数据绑定的对象存放在ObservableCollection集合中
public ObservableCollection<Item> Array = new ObservableCollection<Item>();
public MainPage()
{
Array.Add(new Item("This is the head line, with the pictur 0.png(checked)", "Assets/0.png", true));
Array.Add(new Item("This is the first line, with the pictur 1.png(checked)", "Assets/1.png", true));
Array.Add(new Item("This is the second line, with the pictur 2.png(unchecked)", "Assets/2.png", false));
Array.Add(new Item("This is the third line, with the pictur 3.png(unchecked)", "Assets/3.png", false));
Array.Add(new Item("This is the fourth line, with the pictur 4.png(checked)", "Assets/4.png", true));
this.InitializeComponent();
}
//点击添加按钮,将往Array中添加元素,此时我们可以看到ListView实时更新
private void AddButton_Click(object sender, RoutedEventArgs e)
{
Array.Add(new Item("This is the line you add, with the pictur add.png(unchecked)", "Assets/add.jpg", false));
}
/*
* 当ListView内的内容发生更改时,点击ShowButton,将触发该事件
* 打印出Array的内容,此时我们可以看到Array的内容随着ListView的变化而变化
*/
private void ShowButton_Click(object sender, RoutedEventArgs e)
{
foreach (var item in Array)
{
Debug.WriteLine(item.Content + " " + item.Ischecked);
}
}
}
}
需要注意的地方:
- 定义了两个按钮点击相应事件,主要是为了更好地观察到双向绑定的结果
总结
整个过程就是这样,其中最重要的地方其实就是Item显示实现接口INotifyPropertyChanged,如果需要转换器的话根据目标类型构造转换器;
其实还有一种方法就是使用MvvmLight的ObservableObject,该类已经实现了这个接口,通过继承这个类既可以实现通知界面更新的功能;具体可见另一篇博客UWP—MvvmLight
FYI
项目下载:TwoWayDataBinding
项目下载之后记住把Debug模式从ARM换成X86或X64(根据你自己的机型选择),之前一开始学习的时候不知道这一点,从网上下载下来的项目都运行不了,纠结的一逼(╥╯^╰╥)