array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 [UWP]使用Popup构建UWP Picker - 爱码网
原文:[UWP]使用Popup构建UWP Picker

在上一篇博文《[UWP]不那么好用的ContentDialog》中我们讲到了ContentDialog在复杂场景下使用的几个令人头疼的弊端。那么,就让我们在这篇博文里开始愉快的造轮子之旅吧!

首先要向大家说明:这篇博文主要还是写的构建Picker时的思考过程,如果不感兴趣的,可以直接略过这篇,阅读下一篇《[UWP]如何使用Picker实现一个简单的ColorPicker弹窗》。

首先针对上篇文章中讲到的ContentDialog的几个缺点,先来梳理一下我们对新的弹窗层组件的需求:

  • 能实现正常Dialog的弹出关闭流程(必须的,不然怎么来替代ContentDialog?);
  • 可以支持同时弹出多层弹窗(解决ContentDialog的弊病);
  • 适用于MVVM框架,提供给ViewModel层调用接口(越简单越友好越好,松耦合);
  • 友好的返回值(方便调用方直接获取想要的结果);
  • 要实现ContentDialog类似的可定制化能力(弹出位置,自定义UI,动画等)。

下面的文章里,为了方便描述,我把实现上诉功能的新弹窗层组件称之为Picker(类似于UWP文件选择器的叫法)。

简化一下需求,我们的Picker主要有三个功能规划:

  1. Picker的调用呈现方式为弹出一个类似于ContentDialog的弹窗,但是可以多层级的调用(即多层弹窗);
  2. Picker的业务逻辑实现层遵循共同的调用约束(即实现Picker定义的相关接口),基于此约束实现的MVVM页均可实现Picker的调用方式;
  3. 实现Picker约束的相关类本身实现独立的Pick功能(即调用后返回特定类型值)。

我们简单的类比下,上面对Picker的功能规划其实有点类似于Windows系统中的文件查看逻辑。

在Windows系统中,可以处理某类格式文件(例如.mp4文件)的程序可以向系统申明支持该格式,当系统需要处理这类文件时(例如双击打开.mp4文件),将会调用这个程序(或者询问用户使用哪一个支持该类文件的程序)来处理该文件。

有了明确的功能规划,我们就可以来思考如何实现了。

如何实现Picker的界面层呈现

我们已经说过了,ContentDialog的内部实现其实是依赖Popup,因此我们同样可以用Popup来承载Picker的界面显示。

Popup本身是一个非常基础的组件(UWP中另外一个常用的组件Flyout也是基于Popup实现的),它在UWP应用的可视化树中是处于最顶层的(PopupRoot),且呈现在应用最前面(可以理解为具有最大值的ZIndex)。基于Popup我们可以实现很多不依赖程序主界面的UI功能,并且不受ContentDialog只能同时显示一个的限制。

[UWP]使用Popup构建UWP Picker

这样的话就非常简单了,我们可以构建一个ObjectPicker类,它提供类似ContentDialog类中ShowAsync的方法,调用此方法时创建一个新的Popup,然后将我们要显示的界面元素作为其Child添加到界面上(实际上,结合MVVM框架逻辑,我们使用Frame装载目标页面),在用户完成Pick操作后关闭Popup,并且返回操作结果。

呈现过程的核心,三句代码足以:

    var popup = new Popup();
    //ToDo 装载Picker界面
    popup.IsOpen = true;
    //ToDo 处理Pick交互操作
    popup.IsOpen = false;

当然,涉及到具体实现时,由于我们要考虑到界面呈现的UI交互、位置及动画,实际代码会更多一点。

ObjectPicker类只负责呈现目标页面,它不负责处理任何的业务逻辑。

如何实现Picker的业务逻辑

在我们的规划中,Picker的实际业务逻辑是在Picker页面的逻辑层代码,即ViewModel层中实现的。这样的话,什么时候Picker可以关闭是由其ViewModel决定的。为了使ViewModel的处理结果可以通知到Picker,我们需要让实现Picker功能的ViewModel遵循一个共同的约束。

我们定义这样一个泛型接口:

public interface IObjectPicker<T>
{
    event EventHandler<ObjectPickedEventArgs<T>> ObjectPicked;
    event EventHandler Canceled;
}

其中T代表这个ViewModel支持的Pick对象类型,当用户完成Pick操作时触发ObjectPicked事件,用户取消Pick操作时触发Canceled事件,ObjectPicker类将在Show的时候注册这两个事件来接受ViewModel的处理结果。

如何优雅的调用Picker

当我们实现了一个Picker以后,如何来调用它呢?使用最简单的方法,直接在需要调用Picker的地方new一个ObjectPicker,然后调用ShowAsync来获取返回值?

这看起来没什么问题,但是实际应用中,我们的Picker可能有很多个(文字输入框,颜色选取器等)。我们希望有一个类似于Windows系统注册表的服务,它提供:

  • 不同类型的Picker注册接口及管理;
  • 提供简单友好的Picker调用接口,并且返回Pick结果。

这样的话,我们可以简单的实现一个ObjectPickerService,通过它,我们的调用逻辑会非常的简单:

var pickRet = await pickerService.PickSingleObjectAsync<Color>(typeof(TestColorPickerViewModel).FullName);

这个例子可以在我的开源项目HHChaosToolkit中的Picker部分看到(GitHub链接点这里),同时也是我的下篇博文的主要内容。

这篇文章到这里就结束了,主要还是讲如何构建Picker组件的思考过程,以及我基于对MVVM结构的理解,如何来梳理Picker的架构。下一篇文章我将结合例子介绍一下Picker的实例实现及其调用流程。

写这篇博文着实有些难产,如果有什么地方写的不够好,或者难以理解,欢迎大家指正!谢谢阅读!

相关文章: