现代操作系统应用开发:UWP——DataBinding(三):双向数据绑定

功能简介

示例项目有个一页面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(根据你自己的机型选择),之前一开始学习的时候不知道这一点,从网上下载下来的项目都运行不了,纠结的一逼(╥╯^╰╥)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值