[UWP]不那么好用的ContentDialog
ContentDialog是UWP开发中最常用的组件之一,一个体验良好的UWP应用很难避免不去使用它。博客园里也有许多的文章介绍如何来利用ContentDialog实现各种自定义样式的弹窗界面。不过实际上ContentDialog是一个令人又爱又恨的组件,今天我们就来说一下ContentDialog的缺点。
ContentDialog适合实现轻量级的UI需求,但在处理复杂UI需求时非常难用,例如说:
- 多层级弹窗情况下的UI实现;
- MVVM框架下的UI与业务逻辑的分离;
- 需要弹窗关闭时返回用户操作结果的情况。
上述情况下,如果仍旧使用ContentDialog实现功能需求,会需要很多的代码来完成界面UI交互,这是多余且没有必要的。
多层级弹窗情况下的UI实现
先说第一种情况,多层级弹窗情况下的UI实现。假设我们有一个这样的需求:我们需要弹出一个窗口让用户修改应用设置,同时在用户修改后点击“保存设置”按钮时,弹出一个自定义UI的确认对话框询问用户是否确定保存。
怎么实现呢?很自然的想到,我们可以写两个ContentDialog,一个是设置界面的弹窗,另外一个是自定义UI的确认对话框。先弹出设置弹窗,点击“保存设置”时弹出确认对话框。听起来很完美,逻辑上也没有问题,编码运行一下呢,应用崩溃了...
这是个悲剧,看下VS的崩溃信息:
Only a single ContentDialog can be open at any time.
WTF!!! UWP应用同时只支持唤出一个ContentDialog 么?这也太坑了吧!
不要惊讶,事实上确实如此,关于这点,微软官方给出的解决方案是这样的:
Only one ContentDialog can be shown at a time. To chain together more than one ContentDialog, handle the Closing event of the first ContentDialog. In the Closing event handler, call ShowAsync on the second dialog to show it.
也就是说想要同时显示两个弹窗是不可能的,只能在第一个弹窗关闭后再来打开第二个。
那我们怎么让第二个弹窗出现时仍能保持第一个弹窗的工作状态呢?在这种情况下,我能想到两种解决方法,一是使用MessageDialog代替确认对话框(抛弃掉自定义UI),或者ContentDialog 内使用Frame做Page间导航,需要用户确认时,导航到确认页面。但是毫无疑问,这两种方法都极为影响用户体验。
MVVM框架下的UI与业务逻辑的分离
上面已经说到了ContentDialog 本身的限制使其很难实现复杂UI需求,而这种困难涉及到MVVM框架时情况会更为复杂一些。
我们知道一个好的基于MVVM框架构建的项目一定是结构清晰,UI交互与后台业务逻辑分离的完美状态。ContentDialog本身是一个UI组件,如果只是轻量级的UI需求,比如说只是自定义一个确认对话框,在MVVM项目中使用倒还行。但是如果是一个较为复杂的多(层级)弹窗交互需求,或者弹窗内涉及到导航服务,这种情况下,将View层与ViewModel层间的代码整理清楚就有些困难了。
在之前的一个项目中,我有遇到这样的情况,当时的选择是使用中间人模式,搭建了一个中介类。这个中介类对ViewModel层提供打开或跳转到指定弹窗页面的接口,对View层则实现调度ContentDialog,控制ContentDialog中Frame的页导航。
这样看起来好像也还不错,功能都实现了。但是缺点是仍旧是无法实现多层弹窗,同时要考虑ViewModel调用弹窗的多种情况,实现过程比较复杂,并不能算是一个优雅的解决方式。
需要弹窗关闭时返回用户操作结果的情况
在很多情况下,我们使用弹窗的交互方式并不仅仅是交互需求,而是业务逻辑上的需要,我们想要用户做出交互,并且返回交互结果给后台代码做进一步的处理。
举个例子说,我们做一个绘画应用,我们提供给用户一个调色板来选取画笔颜色,但是这个调色板常驻在画布有些过于侵占用户绘画空间,我们的理想状态是把它做成一个颜色选取弹窗。这个弹窗需要在用户点击更换颜色时弹出来让用户选择颜色,如果用户取消选取颜色则关闭不做任何操作,如果确定选取某一颜色则关闭并返回选取的颜色。如果用ContentDialog来做会怎么样呢?ContentDialog关闭时会返回一个类型为ContentDialogResult的对象来标识用户操作,其定义如下:
//
// 摘要:
// 指定用于指示 ContentDialog 的返回值的标识符。
public enum ContentDialogResult
{
//
// 摘要:
// 未点击按钮。
None = 0,
//
// 摘要:
// 主按钮由用户点击。
Primary = 1,
//
// 摘要:
// 辅助按钮由用户点击。
Secondary = 2
}
那么要实现上面的需求我们需要在ContentDialog中先暂存用户选取的颜色,在拿到返回结果后,如果值为ContentDialogResult.Primary则去取出暂存的颜色,否则不做任何处理。
听起来这已经是个完美的方案了,但是还是有个大问题:我们选取颜色是在一个颜色盘上点击想要的颜色的位置取色,而ContentDialog的返回结果是依赖于点击预定义的几个按钮(PrimaryButton/SecondaryButton/CloseButton),这种情况下,对于UI交互的限制非常大,我们无法实现在颜色盘上取色后立即关闭弹窗,并且返回结果。
结尾
说了这么多,那么有没有一个完美的解决方案呢?你问我有没有,肯定是有的啊!请看下图!
ContentDialog的内部实现其实是依赖Popup,这就让我有了一个大胆的想法,我们程序员最爱干的事情是什么?造轮子呀!ContentDialog不好用,造个好用的新轮子呀!
接下来几篇博文来教大家如何造一个好用的,适用于MVVM框架的弹窗层组件。有兴趣的可以先看一下我的开源项目HHChaosToolkit中的Picker部分(GitHub链接点这里)。
好的,本篇博文到此结束,不知道大家有没有收获,谢谢大家!
[UWP]不那么好用的ContentDialog的更多相关文章
- [UWP]使用Popup构建UWP Picker
在上一篇博文<[UWP]不那么好用的ContentDialog>中我们讲到了ContentDialog在复杂场景下使用的几个令人头疼的弊端.那么,就让我们在这篇博文里开始愉快的造轮子之旅吧 ...
- xamarin UWP中MessageDialog与ContentDialog的区别
MessageDialog与ContentDialog的异同点解析: 相同点一:都是uwp应用上的一个弹窗控件.都能做为弹出应用. 相异点一:所在命名空间不同,MessageDialog在Window ...
- win10 uwp ContentDialog 点确定不关闭
微软的ContentDialog不是一直有,而是UWP新的,可以使用Content放用户控件,使用很好,但是一点不好的是,默认的一点击下面按钮就会退出. 我们有时候需要ContentDialog用户输 ...
- uwp - ContentDialog - 自定义仿iphone提示框,提示框美化
原文:uwp - ContentDialog - 自定义仿iphone提示框,提示框美化 为了实现我想要的效果花费了我很长时间,唉,当初英语不好好学,翻官网翻了半天才找到,分享给刚入门的新手. 首先看 ...
- 张高兴的 UWP 开发笔记:定制 ContentDialog 样式
我需要一个背景透明的 ContentDialog,像下图一样.如何定制?写了一个简单的示例(https://github.com/ZhangGaoxing/uwp-demo/tree/master/C ...
- win10 UWP MessageDialog 和 ContentDialog
我之前开发一个软件 winMarkdown,这个软件在关闭需要提示用户还没有保存东西,需要保存,如果用户选择退出,那么把数据存放. 在Metro程序中,没有传统的窗口,当我们要用需要交互的消息提示时, ...
- Windows UWP开发系列 – MessageDialog 和 ContentDialog
MessageDialog 在Metro程序中,没有传统的窗口,当我们要用需要交互的消息提示时,在Win8时代,引入了一个MessageDialog来取代常用的MessageBox.使用方法如下: p ...
- UWP开发必备以及常用知识点总结
一直在学UWP,一直在写Code,自己到达了什么水平?还有多少东西需要学习才能独挡一面?我想对刚接触UWP的开发者都有这种困惑,偶尔停下来总结分析一下还是很有收获的! 以下内容是自己开发中经常遇到的一 ...
- Xamarin.Android和UWP之MVVM的简单使用(二)
0x01 前言 前面一篇,Xamarin.Android和UWP之MVVM的简单使用(一),主要讲了MvvmLight的简单使用 这篇主要讲讲MvvmCross的简单使用,例子的话,还是和上篇的一样. ...
随机推荐
- PHP实现JS点击点击定位
点击class='women' 定位到 class='m=foot'$(".women").on('click',function(){ $("html, body&qu ...
- RANSAC介绍(Matlab版直线拟合+平面拟合)
https://blog.csdn.net/u010128736/article/details/53422070
- Delphi RTTI的应用(一)
1.获取DbgrdiEH 某一个选项的属性.加载到ComBox procedure TForm1.FormCreate(Sender: TObject); var PropInfo: PPropInf ...
- redis安装--单机
本例基于CentOS7.2系统安装 环境需求: 关闭防护墙,selinux 安装好gcc等编译需要的组件 yum -y install gcc c++ 到redis官网下载合适版本的redis安装包, ...
- Jquery中父,子页面之间元素获取及方法调用
一.jquery 父.子页面之间页面元素的获取,方法的调用: 1. 父页面获取子页面元素: 格式:$("#iframe的ID").contents().find("#if ...
- sessionStorage实现note的功能
功能图如图所示: 文本域中输入点击保存后的结果如图所示: 点击读取后的结果图: 选择山羊对应的按钮进行修改并点击保存后的结果: 选择山羊养对应的单选按钮进行删除操作后的结果图: 点击清空后的结果: 源 ...
- Jenkin配置执行远程shell命令
转载自 http://www.cnblogs.com/parryyang/p/6261730.html 在利用jenkins进行集成化部署的时候,我们在部署生成的war包时,往往需要进行一些备份,或者 ...
- spring boot 整合 elasticsearch 5.x
spring boot与elasticsearch集成有两种方式.一种是直接使用elasticsearch.一种是使用data中间件. 本文只指针使用maven集成elasticsearch 5.x, ...
- CF 317 A. Lengthening Sticks(容斥+组合数学)
传送门:点我 A. Lengthening Sticks time limit per test 1 second You are given three sticks with po ...
- 100-days: sixteen
Title: The world's most expensive cities 生活成本最高的城市 For the first time in its 30-year history, the Wo ...