[UWP]不那么好用的ContentDialog

简介: 原文:[UWP]不那么好用的ContentDialogContentDialog是UWP开发中最常用的组件之一,一个体验良好的UWP应用很难避免不去使用它。博客园里也有许多的文章介绍如何来利用ContentDialog实现各种自定义样式的弹窗界面。
原文: [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

ContentDialog的内部实现其实是依赖Popup,这就让我有了一个大胆的想法,我们程序员最爱干的事情是什么?造轮子呀!ContentDialog不好用,造个好用的新轮子呀!

接下来几篇博文来教大家如何造一个好用的,适用于MVVM框架的弹窗层组件。有兴趣的可以先看一下我的开源项目HHChaosToolkit中的Picker部分(GitHub链接点这里)。

好的,本篇博文到此结束,不知道大家有没有收获,谢谢大家!

目录
相关文章
|
C# 程序员
[UWP]做个调皮的BusyIndicator
原文:[UWP]做个调皮的BusyIndicator 1. 前言 最近突然想要个BusyIndicator。做过WPF开发的程序员对BusyIndicator应该不陌生,Extended WPF Toolkit 提供了BusyIndicator的开源实现,Silverlight Toolkit也有一个,这次想要把这个控件移植到UWP中。
933 0
[UWP]了解IValueConverter
原文:[UWP]了解IValueConverter 1. 前言 IValueConverter是用于数据绑定的强大的武器,它用于Value在Binding Source和Binding Target之间的转换。
974 0
[UWP]使用Acrylic(亚克力)
原文:[UWP]使用Acrylic(亚克力) 1. 前言 在 如何使用Fluent Design System 这篇文章里已经简单介绍过Reveal的用法,这篇再详细介绍其它内容。 自Windows 8 放弃Aero后,群众对毛玻璃回归的呼声一致都很大。
1532 0
|
搜索推荐 API 开发者
简单说一下UWP中的JumpList
原文:简单说一下UWP中的JumpList   在Windows10的10856这个版本中,微软为桌面版提供了一组新的应用交互方式,磁贴和Toast通知的个性化都有了一定的改善。针对磁贴方面,微软为我们提供了一组新的API来扩充我们对应用的交互方式——JumpList。
836 0
|
API C# Windows
起调UWP的几种方法
原文:起调UWP的几种方法 由于种种原因吧,我需要使用一个WPF程序起调一个UWP程序,下面总结一下,给自己个备份。 启动UWP程序的关键是协议启动 给我们的UWP应用添加一个协议,like this: 然后使用协议启动该UWP有一下几种方式: 1.
1027 0
|
数据安全/隐私保护 安全 API
win10 uwp ApplicationView
原文:win10 uwp ApplicationView 本文和大家介绍一个重要的类,他可以用来设置窗口,如设置启动大小,设置是否允许截图,是否进入全屏,所有和窗口有关的,都可以在他这里设置。
1211 0
|
前端开发
win10 UWP 蜘蛛网效果
原文:win10 UWP 蜘蛛网效果 我看见了知乎首页登录背景和普通的地球人写的博客,发现了个好看的效果。 那么我来告诉大家如何做这个效果。
1132 0
|
UED 容器
[UWP]了解模板化控件(2.1):理解ContentControl
原文:[UWP]了解模板化控件(2.1):理解ContentControl UWP的UI主要由布局容器和内容控件(ContentControl)组成。布局容器是指Grid、StackPanel等继承自Panel,可以拥有多个子元素的类。
1245 0
|
C# 开发者
[UWP]了解模板化控件(5):VisualState
原文:[UWP]了解模板化控件(5):VisualState 1. 功能需求 使用TemplatePart实现上篇文章的两个需求(Header为空时隐藏HeaderContentPresenter,鼠标没有放在控件上时HeaderContentPresent半透明),虽然功能已经实现,但这样实现的话基本上也就别想扩展了。
1208 0
|
C# Windows
[UWP]了解模板化控件(3):实现HeaderedContentControl
原文:[UWP]了解模板化控件(3):实现HeaderedContentControl 1. 概述 来看看这段XMAL: 是不是觉得它们中出了一个叛徒?这个示例中除了ListBox控件其它都自带Header,但是ListBox没有Header属性,只好用一个TextBlock模仿它的Header。
1190 0