现代操作系统应用开发:UWP——DataBinding(二):数据绑定+转换器

功能简介

在数据绑定的时候,我们有时候会遇到不能直接绑定的情况,如Checkbox的IsChecked属性不能直接绑定一个布尔值,Image的Source属性不能直接绑定到一个string上,这时候就需要添加转换器完成数据绑定

示例项目将编写两个转换器,使Checkbox的IsChecked属性通过转换器绑定一个布尔值上,Image的Source属性通过转换器绑定到一个string上;

示例项目将使用到部分文件存储和双向绑定的内容,但这只是为了演示转换器的功能,本文的重点在于CheckBoxConverter类和ImageConverter的实现,如果想要了解文件存储和双向绑定的内容,可以参考另一篇博客:UWP文件管理UWP数据绑定——双向绑定

实现效果

  • 启动程序时:Item的属性值通过转换器给Image和Checkbox赋值

  • 点击按钮更改图片,Item的Source属性变化,Image的Source属性值实时更新

实现过程

添加一个类CheckBoxConverter

该类将继承接口IValueConverter,同时实现接口的两个函数

/*
* value为需要转化的值
* targetType为要转化成的值的类型
* parameter为转化时传递的参数,
* 根据value的值,返回一个targetType类型的值
*/
public object Convert(object value, Type targetType, object parameter, string language){
    ......
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
    ......
}

示例代码中的CheckBoxConverter的功能是将布尔值转化为Checkbox的IsChecked属性值,具体代码如下:

//CheckBoxConverter.cs
namespace DataBindingWithConverter
{
    /*
     * 转化器,将布尔值转化为Checkbox的IsChecked属性(System.Nullable`1[System.Boolean])
     */
    public class CheckBoxConverter : IValueConverter
    {
        /*
        * value为Item的Ischecked 属性,布尔值
        * targetType为Checkbox的Ischecked 属性的类型
        * parameter为转化时传递的参数,这里为空
        */
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            /*
             * bool? 表示isChecked可以取null
             * value as bool? 将value转化为布尔值然后返回,如果不能转化,则返回null
             */
            bool? isChecked = value as bool?;
            /*
             * 实际上这里返回的并不是targetType类型的值,而是布尔值
             * 但是在代码中返回值为Object,布尔值将被强制转化
             * 注意:在类型不能强制转化的情况下,应该根据targetType的类型返回返回需要的值
             */
            if (isChecked == null || isChecked == false)
            {
                return false;
            }
            else
            {
                return true;
            }
        }

        /*
         * 因为是单向绑定,所有并不需要编写ConvertBack函数
         * 如果使用了双向绑定,可以参考上面函数的写法添加ConvertBack函数的代码
         */
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}

需要注意的地方:

  • 继承接口IValueConverter
  • 根据value和targetType定义Convert函数

同理添加一个类ImageConverter

//ImageConverter.cs
namespace DataBindingWithConverter
{
    class ImageConverter : IValueConverter
    {
        //string转ImageSource(Image的Source属性)
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            string source = value as string;
            ImageSource imageSource = new BitmapImage(new Uri(source));
            return imageSource;
        }

        //Mode = Oneway,所以不用管ConvertBack的内容
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
}

新建类Item.cs

//Item.cs
namespace DataBindingWithConverter
{
    /*
     * Item是我们自定义的一个类型,包含三个属性,对应三个控件的属性
     * Source --> Image的Source
     * Ischecked --> Checkbox的checked
     * 这里继承了接口INotifyPropertyChanged,当Item某一属性值发生更改时,发出通知
     * 导致控件的属性也实时更改
     * 这里主要是为了测试转化器才这么使用的,可以暂时不用管INotifyPropertyChanged的作用
     */
    public class Item : INotifyPropertyChanged
    {
        private string _source;
        private bool _ischecked;

        public string Source
        {
            get => _source;
            set { _source = value; OnPropertyChanged("Source"); }
        }
        public bool Ischecked
        {
            get => _ischecked;
            set { _ischecked = value; OnPropertyChanged("Ischecked"); }
        }


        public Item(string source,bool ischecked)
        {
            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));
            }
        }
    }
}

在MainPage.xaml.cs中添加代码

//MainPage.xaml.cs
namespace DataBindingWithConverter
{
    public sealed partial class MainPage : Page
    {
        public Item MyItem;
        //LocalFolder文件存储
        private string prefix = "ms-appdata:///local/";

        public MainPage()
        {
            MyItem = new Item("ms-appx:///Assets/flash.jpg", true);
            this.InitializeComponent();
        }

        private async void ChangeImage(object sender, RoutedEventArgs e)
        {
            var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
            openPicker.FileTypeFilter.Add(".jpg");
            StorageFile file = await openPicker.PickSingleFileAsync();

            //LocalFolder文件存储
            Windows.Storage.StorageFolder localFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
            StorageFile fileCopy = await file.CopyAsync(localFolder, file.Name, NameCollisionOption.ReplaceExisting);

            //设置MyItem的Source,此时将使用转化器转化为Image的Source值
            MyItem.Source = prefix + file.Name;
        }
    }
}

需要注意的地方:

  • 选择图片后需要把图片保存在LocalFolder,这里主要是因为权限问题
  • 将MyItem的Source值实时更新为新的地址值

在MainPage.xaml中添加代码

首先,需要在Grid的上面添加代码:

<!-- 
    将CheckboxConverter类添加到资源,因为CheckboxConverter和MainPage的命名空间一样,所有使用local
    x:key可以设置为任何你喜欢的值,下面将通过这个值指向CheckboxConverter
-->
<Page.Resources>
    <local:CheckBoxConverter  x:Key="ConvertCheck"></local:CheckBoxConverter>
    <local:ImageConverter  x:Key="ConvertImage"></local:ImageConverter>
</Page.Resources>

然后在Grid中添加控件并绑定,代码如下:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <StackPanel>
        <Image Source="{x:Bind MyItem.Source,Converter={StaticResource ConvertImage},Mode=OneWay}" ></Image>
        <CheckBox  IsChecked="{x:Bind MyItem.Ischecked,Converter={StaticResource ConvertCheck},Mode=OneWay}"  Content="Whether the CheckBox is checked is depend on the Item."></CheckBox>
        <Button Content="ChangePicture" Click="ChangeImage" Width="300"></Button>
    </StackPanel>
</Grid>

需要注意的地方:

  • 一开始资源文件的声明

  • CheckBox的IsChecked属性的绑定,Image的Source属性的绑定

总结

总的说来,转化器 + 数据绑定的大致过程就是:

  1. 根据需要转化的值和目标类型编写转化器
  2. 在xaml.cs中声明资源文件
  3. 绑定属性是添加转化器

其实,选择图片后还可以按下面的设置更新Image控件:

var openPicker = new Windows.Storage.Pickers.FileOpenPicker();
openPicker.FileTypeFilter.Add(".jpg");
file = await openPicker.PickSingleFileAsync();

//将图片赋给右侧的Image
if (file != null)
{
    BitmapImage bitmap = new BitmapImage();
    using (var stream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read))
    {
        bitmap.SetSource(stream);
    }
    //这里的MyImage为Image的x:Name值
    MyImage.Source = bitmap;
}

但是为什么不这么做呢?主要是因为两点,一,本文主要是为了演示如何使用转换器,所以更新Item.Source的值然后再使用转换器更新Image;二,在之后使用了MvvmLight之后,你会发现将视图和功能分离的重要性ヽミ ´∀`ミノ<

Tips

可能你和我一样不知道Convert和ConvertBack的目标类型是什么,总是搞混,这时候其实我们可以通过Debug.WriteLine()方法打印出目标类型

using System.Diagnostics;
Debug.WriteLine(targetType);

FYI

项目下载:DataBindingWithConverter

项目下载之后记住把Debug模式从ARM换成X86或X64(根据你自己的机型选择),之前一开始学习的时候不知道这一点,从网上下载下来的项目都运行不了,纠结的一逼(╥╯^╰╥)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值