博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
博客园客户端UAP开发随笔--自定义控件的左膀右臂
阅读量:4994 次
发布时间:2019-06-12

本文共 4905 字,大约阅读时间需要 16 分钟。

前言

我们上一次说到了App的精灵:自定义控件。这一次,我们接着这一话题,说说自定义控件的两个得力助手:

  • 选择器 - TemplateSelector
  • 转换器 – Converter

这两个东西能帮助自定义控件更为简单方便地被使用,所以必须掌握。

数值转换器 Converter

这个大家可能不陌生,因为在MSDN里,介绍到Data Binding时,总会顺带着介绍一下数据转换,比如这个网页:

最后的那个StringFormatter就是。

在博客园UAP中,我们使用了好几个Converter,每个Converter实际上是一段cs类,派生自IValueConverter接口。它们都放在CNBlogs.Shared项目的ControlHelper目录中。我们用其中的两个做例子来说明一下。

Bool/Visibility的转换

我们看这段代码:

public class BoolToVisibilityConverter : IValueConverter{        public object Convert(object value, Type targetType, object parameter, string language)        {            return (bool)value ? Visibility.Visible : Visibility.Collapsed;        }        public object ConvertBack(object value, Type targetType, object parameter, string language)        {            throw new NotImplementedException();        }}

功能很直接,就是把bool值转换成Visibility的枚举值,然后绑定到一个控件的某个元素上,比如,在XAML里:

……
……                    

上面这段XAML是一个自定义控件的style描述,控件本身是“收藏”页中的“关注的博主”控件,其目的是:当HasNew字段值是true时,在博主的头像左侧显示一个红色的小星星,表示该博主有新的博客发表了,你如果关注了该博主,可以点进去看他的新博客。当HasNew是false时,不显示小星星,你就不需要进去看一圈,发现没有新博客然后失望地离开了。

有的人也许会说:我在FavoriteAuthorControl.cs的code里,直接取HasNew值,看其是true还是false,然后直接用code写Visibility = Visiable or Collapsed即可。

这样做当然也可以啦,但是有几个不方便的地方:

1)你需要写code

2)读你的程序的人,如果没读到你的code,就不知道这个逻辑

3)你需要命名那个TextBlock (x:Name=…)然后在code里用GetChildTemplate(“…")来得到这个控件,再指定其Visibility值。

4)在其它控件中,你依然还要写code做类似的事

而用我们推荐的方法,其好处显而易见:

1)在XAML中绑定即可,no code

2)这个转换器可以重用

3)无需更多定义,在binding阶段一次性解决(这也是WPF的优点之一),性能无需考虑

4)可读性极好

bool/string转换器

再举一个例子巩固一下,上code:

class NightModeLabelConverter : IValueConverter{        public object Convert(object value, Type targetType, object parameter, string language)        {            bool bValue = (bool)value;            if (bValue)            {                return "日间模式";            }            else            {                return "夜间模式";            }        }        public object ConvertBack(object value, Type targetType, object parameter, string culture)        {            throw new NotImplementedException();        }}

在XAML中这样使用:

这个绑定过程会先检查Setting中NightMode的值,如果是True,会在按钮下方显示“日间模式”;如果是false,会显示“夜间模式”。

模板选择器 TemplateSelector

模板选择器很少有人用到,因为介绍它的文档很少,到目前为止我们没发现,也是一个偶然的机会知道有这么个东西的,很好用!记得有几次面试,我们都问到了这个问题:如果一条新闻有图片,另一条新闻没图片,你准备如何显示这两个Control呢?如下图所示,上面那个有图片(特意用红色矩形标记了一下),下面那个没图片。

我们得到两种回答:

1)做成一个通用的Control,然后根据有无图片的URL自动显示右侧的图片

2)用code在自定义空间里控制右侧图片是否显示

当然可以!这些都能实现这个目的。但要注意图片左侧还有一条灰色竖线哟。

我们今天推荐一个更为标准通用的方法:TemplateSelector。

先上code:

namespace CNBlogs.ControlHelper{    class NewsControlTemplateSelector : DataTemplateSelector    {        public DataTemplate dtHasImage { get; set; }        public DataTemplate dtNoImage { get; set; }        protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)        {            CNBlogs.DataHelper.DataModel.News news = item as CNBlogs.DataHelper.DataModel.News;            if (string.IsNullOrEmpty(news.TopicIcon))            {                return dtNoImage;            }            return dtHasImage;        }    }}

在Shared project中,ControlHelper目录下,有个NewsControlTemplateSelector.cs。它从DataTemplaterSelector父类派生出来,先定义了两个DataTemplate: dtHasImage和dtNoImage,分别对应有无图片的两种情况。然后在SelectTemplateCore重写方法中,先获得news实例,判断TopicIcon是否存在,如果存在,返回dtHasImage;否则返回dtNoImage。

在MainPage.xaml中,这样使用:

......
......

首先在Page.Resource中定义两个Template,给出两个不一样的Key值,一个叫做“NewsNoImageTemplate”,另一个叫做“NewsHasImageTemplate”,分别对应两个自定义control:NewsTitleTextControl和NewsTitleTextImageControl (在Theme\Generic.xaml中定义的,一个只有标题文本,另一个有标题文本和右侧图片)。

然后在News PivotItem的ListView中这样写:

......

ListView.ItemTemplateSelector用于定义当前的新闻用什么样的模板来显示。注意下面的语法:

1)ControlHelper:NewsControlTemplateSelector对应第一段cs代码的类名

2)dtHasImage/dtNoImage对应cs代码中的两个返回值

3)StaticResource NewsHasImageTemplate对应Page.Resources中的x:Key=”NewsHasImageTemplate”,间接对应到了有图片的自定义控件模板。

即:控件<—>资源文件<—>选择器。这三者的关系容易搞混,尤其是名字,特别容易起错,以至于最后自己都不记得什么对应什么。建议是控件用Control做结尾,如NewTitleTextControl;资源文件的Key用Template做结尾,如NewsNoImageTemplate;选择器用dt做开始,如dtNoImage。这样的话,如果有图片,Selector就会返回dtHasImage,对应到了本页资源中的StaticResource NewHasImageTemplate,从而使用NewsTitleTextImage自定义控件来显示该条新闻。

小结

好了,掌握了第一个转换器,我们不用再每个control里都写code了,直接在XAML中绑定即可。掌握了第二个选择器,我们可以充分分解页面逻辑,把它们颗粒化到一个合理的程度,不需要再考虑如何用一个控件显示两种或多种样式。

但是要注意,在以前的“App精灵”随笔中,提到的PostControl控件,有时要显示作者头像,有时要显示“朕已阅”等等,如果你要做成5个Control,再用TemplateSelector来选择就是不对的了。基本原则是:在一个ListView中,如果有两种以上的样式选择,用TemplateSelector;在两个页面中,用TemplateBinding外部配置来指定要不要显示某个元素,比如AuthorAvatar.Visibility = {TemplateBinding ShowAvatar},使用它时在两个页面中分别直接指定Visable或Collapsed即可,从而允许使用一个控件搞定5种情况。

在Windows Phone 8.1和Windows 8.1中,一点儿区别都没有,所以我们把这些cs都放在了shared project中,以便能够在两个项目中共享。

 

分享代码,改变世界!

 

Windows Phone Store App link:

Windows Store App link:

GitHub open source link:

MSDN Sample Code:

 

MS-UAP

2015/1/5

转载于:https://www.cnblogs.com/ms-uap/p/4201334.html

你可能感兴趣的文章
升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署
查看>>
Android:onNewIntent()触发机制及注意事项
查看>>
珠宝公司之感想
查看>>
项目问题
查看>>
scss侦听并压缩
查看>>
我有接口文档, 你有酒吗?
查看>>
iOS - Push 通知推送
查看>>
[FJOI2007]轮状病毒
查看>>
Azure AADSTS7000215 其中一种问题的解决
查看>>
关于吃苦
查看>>
uva 1629切蛋糕(dp)
查看>>
生成awr报告
查看>>
cocos2d-x 3.0rc2 对于每个包执行情况的重要平台 (超级方便)
查看>>
Android 深入解析光传感器(二)
查看>>
Ansible@一个高效的配置管理工具--Ansible configure management--翻译(八)
查看>>
【bzoj4552/Tjoi2016&Heoi2016】排序——二分+线段树/平衡树+线段树分裂与合并
查看>>
Windows Internals学习笔记(八)IO系统
查看>>
sql插件,SQLPrompt
查看>>
Objetive-C 属性和线程安全
查看>>
mybatis pagehelper实现分页
查看>>