WPF的MVVM框架Stylet开发文档 17.设计模式支持

2023-10-31

17.设计模式支持

介绍

“设计模式”或“设计时”是指当您的项目加载到 Visual Studio XAML 设计器或 Expression Blend 中时,您将看到 XAML 的渲染版本。大多数时候,设计者不会尝试评估您的任何绑定或为它们提供任何 IntelliSense。然而,通过一些配置,您可以获得可爱的 IntelliSense,并在您的视图中显示来自您的 ViewModel 的一些虚拟值。

Stylet 对设计模式有一些基本支持。本文对其进行了记录,并提供了有关如何使用它和利用现有 XAML 功能来增强设计时体验的说明。

此处显示的所有示例都可以在DesignMode 示例项目中“准备运行” 。

仅限 IntelliSense,无绑定

这是最基本的技术,您需要做的额外工作很少。您将获得绑定的 IntelliSense(至少在 Visual Studio 2013 及更高版本中),但您不会在视图中看到来自 ViewModel 的任何虚拟数据。

首先,您需要在视图的根目录中进行以下声明。如果您已在 Visual Studio 2013 中创建了 UserControl,则默认情况下会添加这些控件。

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
mc:Ignorable="d" 

您还需要为 ViewModel 添加命名空间:

xmlns:vms="clr-namespace:DesignMode.ViewModels"

一旦你掌握了这个,你就需要一条额外的魔法线。这会告诉 XAML 设计器DataContext此视图的 是您的SampleViewModel,并且绑定 IntelliSense 应该使用此属性:

d:DataContext="{d:DesignInstance vms:SampleViewModel}"

把它们放在一起,你最终会得到这样的东西:

<UserControl x:Class="DesignMode.Views.SampleView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d"
             xmlns:vms="clr-namespace:DesignMode.ViewModels"
             d:DataContext="{d:DesignInstance vms:SampleViewModel}">
   ...
</UserControl>

Intellisense 和 Dummy Data,让 Designer 实例化 ViewModel

此技术与前一个技术非常相似,只是我们让 XAML 设计器为我们实例化 ViewModel。设计人员将使用此 ViewModel 实例从中获取绑定的虚拟数据。

为了让设计者能够做到这一点,ViewModel 必须有一个无参数的构造函数。这既是福也是祸。好的一面是,它为您提供了一个将一些虚拟数据注入 ViewModel 的属性以供设计人员使用的好地方。不利的一面是您的 ViewModel 现在包含仅供设计人员使用的代码…

请注意,在设计时无法访问 IoC 容器(并且任何请求访问的人都将被带回并…处理)。因此,如果您的 ViewModel 有任何依赖项,它们将在设计时不可用。通常这不是问题:只访问属性(不调用任何方法),因此您实际上不应该做任何需要访问您的依赖项之一的事情。请记住它。

以这种方式编写以支持设计模式的示例 ViewModel 可能如下所示:

public class SampleViewModel
{
    private readonly IUserService userService;

    public string CurrentUserName { get; private set; }

    public SampleViewModel()
    {
        this.CurrentUserName = "Dummy Username";
    }

    public SampleViewModel(IUserService userService)
    {
        this.userService = userService;
        this.CurrentUserName = this.userService.CurrentUser.UserName;
    }
}

请注意,StyletIoC 将始终选择其可以解析的参数最多的构造函数,因此它还将调用接受IUserService. 另一方面,设计者将始终调用无参数构造函数。

如果您的 ViewModel 通常只有一个无参数构造函数,您可以使用Execute.InDesignMode,如下所示:

public class SampleViewModel
{
    public string SomeText { get; set; }

    public SampleViewModel()
    {
        if (Execute.InDesignMode)
            this.SomeText = "Dummy Text";
        else
            this.SomeText = "Actual Text";
    }
}

无论哪种方式,一旦您获得了设计人员可以使用的带有无参数构造函数的 ViewModel,您就可以告诉设计人员使用以下方法实例化它:

d:DataContext="{d:DesignInstance vms:SampleViewModel, IsDesignTimeCreatable=True}"

或者,完整的:

<UserControl x:Class="DesignMode.Views.SampleView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d"
             xmlns:vms="clr-namespace:DesignMode.ViewModels"
             d:DataContext="{d:DesignInstance vms:SampleViewModel, IsDesignTimeCreatable=True}">
   ...
</UserControl>

Intellisense 和虚拟数据,使用 ViewModelLocator

以前的方法有一个很大的缺点:它要求您的 ViewModel 了解设计模式,并且包含仅在设计时调用的代码。一些人认为这是一种巨大的代码味道。

另一种方法是使用 ViewModelLocator - 一个仅在设计时使用的类,它可以实例化和配置您的 ViewModel。这意味着任何仅限设计时的本地都可以进入 ViewModelLocator,而不会进入各个视图。

如果这听起来很复杂,请耐心等待。这一切都应该在一分钟内变得有意义。

首先,让我们获取一个示例 ViewModel:

public class SampleViewModel
{
    private readonly IUserService userService;

    public string CurrentUserName { get;set; }

    public SampleViewModel(IUserService userService)
    {
        this.userService = userService;
        this.CurrentUserName = this.userService.CurrentUser.UserName;
    }
}

接下来,我们需要一个 ViewModelLocator。这是一个简单的类,每个 ViewModel 包含一个我们可能希望在设计时访问的属性:

public class ViewModelLocator
{
    public SampleViewModel SampleViewModel
    {
        get
        {
            var vm = new SampleViewModel();
            vm.CurrentUserName = "Dummy Username";
            return vm;
        }
    }
}

请注意 ViewModel 是如何仅在需要时实例化的?这是因为 ViewModelLocator 本身会在运行时被实例化,但它的属性只会在设计时被访问。

接下来,让我们将它添加到我们应用程序的资源中,以便我们的视图可以使用它:

<Application x:Class="DesignMode.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:s="https://github.com/canton7/Stylet"
             xmlns:local="clr-namespace:DesignMode">
    <Application.Resources>
        <s:ApplicationLoader>
            <s:ApplicationLoader.Bootstrapper>
                <local:Bootstrapper/>
            </s:ApplicationLoader.Bootstrapper>
            
            <local:ViewModelLocator x:Key="ViewModelLocator"/>
        </s:ApplicationLoader>
    </Application.Resources>
</Application>

…然后在我们的视图中使用它:

<UserControl x:Class="DesignMode.Views.SampleView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d"
             xmlns:vms="clr-namespace:DesignMode.ViewModels"
             d:DataContext="{Binding Source={StaticResource ViewModelLocator}, Path=SampleViewModel}">
   ...
</UserControl>

在设计时启用/禁用按钮

在上面的所有示例中,我们只绑定了 View DataContext:我们没有对其View.ActionTarget做任何事情。这意味着按钮的启用将不会反映守卫属性的值,如果它存在——它将始终启用。

注意:View.ActionTarget默认情况下,Stylet在实例化 View 时会绑定到对应的 ViewModel。但是,在设计时,Stylet 不负责实例化视图,因此View.ActionTarget未绑定。

如果你想让按钮的 enabledless 反映它的 guard 属性,你需要添加s:View.ActionTarget="{Binding}"到你的视图,例如

<UserControl x:Class="DesignMode.Views.SampleView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:s="https://github.com/canton7/Stylet"
             mc:Ignorable="d"
             xmlns:vms="clr-namespace:DesignMode.ViewModels"
             d:DataContext="{d:DesignInstance vms:SampleViewModel, IsDesignTimeCreatable=True}"
             s:View.ActionTarget="{Binding}">
   ...
</UserControl>

使用替代 ViewModel

_另一个解决“我的 ViewModel 知道设计时间,而它不应该知道”_的问题是让你的 View 实现一个接口(一个真实的接口,或者你头脑中的假接口),然后你编写另一个设计时间-only View 实现相同的接口,并包含虚拟数据。然后在设计时以相同的方式绑定到它d:DataContext="{d:DesignInstance vms:DummyViewModel, IsDesignTimeCreatable=True}":不过,对于大多数开发人员来说,这开销太大了。

WPF 也有设计时数据的概念,例如参见

为什么 Stylet 不能自动找到我的 ViewModel?

由于 Stylet 能够获取 ViewModel,并找到并实例化它的 View,您可能会想问为什么它不能以相反的方式执行此操作:也就是说,在设计时,自动为给定的 View 找到正确的 ViewModel ,并使用正确的依赖项实例化它。这是一个非常糟糕的主意的原因有很多:

  1. 我们需要添加一种将 View 名称转换为 ViewModel 名称的方法,这会增加复杂性ViewManager(特别是对于提供自己的 View 的任何人ViewManager)。
  2. 我们需要IViewManager在设计时实例化一个适当的实现。由于用户可以提供他们自己的实现,这将意味着启动整个 IoC 容器。由于这依赖于正确设置引导程序的 Assemblies 属性,因此我们需要启动整个引导程序。这有可能产生严重的副作用(想想启动网络提交、文件系统访问等服务)。
  3. 我们需要提供一个 ViewModel 及其所有依赖项。这意味着实例化服务,这可能会产生严重的副作用。
  4. 无论如何,ViewModel 可能不会包含合适的虚拟数据,所以我们没有得到太多。
  5. 由于我们过于聪明而导致某些服务以错误的方式启动而导致 Designer 错误(或更糟,具有网络/文件系统副作用)调试起来很痛苦,我们不应该将其强加于人。

s:View.Model 和嵌入式视图

如果您的视图中有一个嵌入式视图(例如<ContentControl s:View.Model="{Binding SomeChildViewModel}"/>),那么 Stylet 将只显示一条消息,类似于“View for ViewModelType.SomeChildViewModel”,而不是尝试定位正确的视图。这与我们不自动定位 ViewModel 的原因非常相似:这意味着启动 IoC 容器(我们需要找到用户的IViewManager实现),这意味着运行引导程序,这让我们可以做非常危险的事情。最好避免。

项目原地址:https://github.com/canton7/Stylet
当前文档原地址:https://github.com/canton7/Stylet/wiki/Design-Mode-Support

上一篇:WPF的MVVM框架Stylet开发文档 16.监听INotifyPropertyChanged接口
下一篇:WPF的MVVM框架Stylet开发文档 18.记录 Logging

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WPF的MVVM框架Stylet开发文档 17.设计模式支持 的相关文章

  • SSH 主机密钥指纹与模式 C# WinSCP 不匹配

    我尝试通过 WinSCP 使用 C 连接到 FTPS 服务器 但收到此错误 SSH 主机密钥指纹 与模式不匹配 经过大量研究 我相信这与密钥的长度有关 当使用 服务器和协议信息 下的界面进行连接时 我从 WinSCP 获得的密钥是xx xx
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 如何在我的应用程序中使用 Windows Key

    Like Windows Key E Opens a new Explorer Window And Windows Key R Displays the Run command 如何在应用程序的 KeyDown 事件中使用 Windows
  • 为什么 POSIX 允许在只读模式下超出现有文件结尾 (fseek) 进行搜索

    为什么寻找文件结尾很有用 为什么 POSIX 让我们像示例中那样在以只读方式打开的文件中进行查找 c http en cppreference com w c io fseek http en cppreference com w c io
  • WPF 从主线程以外的其他线程截屏

    我有一个线程用于侦听 WPF 应用程序的命令 如果 WPF 应用程序收到截取屏幕截图的命令 则任务将移交给 screenshotService 我在互联网上的某个地方找到了一些代码来截取屏幕截图 似乎可以工作 但我还没有想清楚 我无法从另一
  • HttpClient 像浏览器一样请求

    当我通过 HttpClient 类调用网站 www livescore com 时 我总是收到错误 500 可能服务器阻止了来自 HttpClient 的请求 1 还有其他方法可以从网页获取html吗 2 如何设置标题来获取html内容 当
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J
  • 按字典顺序对整数数组进行排序 C++

    我想按字典顺序对一个大整数数组 例如 100 万个元素 进行排序 Example input 100 21 22 99 1 927 sorted 1 100 21 22 927 99 我用最简单的方法做到了 将所有数字转换为字符串 非常昂贵
  • 在 ASP.Net Core 2.0 中导出到 Excel

    我曾经使用下面的代码在 ASP NET MVC 中将数据导出到 Excel Response AppendHeader content disposition attachment filename ExportedHtml xls Res
  • 初始化变量的不同方式

    在 C 中初始化变量有多种方法 int z 3 与 int 相同z 3 Is int z z 3 same as int z z 3 您可以使用 int z z 3 Or just int z 3 Or int z 3 Or int z i
  • 像“1$”这样的位置参数如何与 printf() 一起使用?

    By man I find printf d width num and printf 2 1 d width num 是等价的 但在我看来 第二种风格应该与以下相同 printf d num width 然而通过测试似乎man是对的 为什
  • AccessViolationException 未处理

    我正在尝试使用史蒂夫 桑德森的博客文章 http blog stevensanderson com 2010 01 28 editing a variable length list aspnet mvc 2 style 为了在我的 ASP
  • 检查 url 是否指向文件或页面

    我们需要以下内容 如果文件确实是文件 则从 URL 下载该文件 否则 如果它是一个页面 则什么也不做 举个简单的例子 我有以下命令来下载文件 My Computer Network DownloadFile http www wired c
  • 在 URL 中发送之前对特殊字符进行百分比编码

    我需要传递特殊字符 如 等 Facebook Twitter 和此类社交网站的 URL 为此 我将这些字符替换为 URL 转义码 return valToEncode Replace 21 Replace 23 Replace 24 Rep
  • 作为字符串的动态属性名称

    使用 DocumentDB 创建新文档时 我想设置属性名称动态地 目前我设置SomeProperty 像这样 await client CreateDocumentAsync dbs db colls x new SomeProperty
  • 如何在.NET Core上直接调用F#编译器?

    UPD 我想直接从 NET Core SDK 调用 F 编译器 即 fsc 我了解 dotnet build co 但当我只需要编译一个简单的问题时 即 fsc file fs 就足够的情况下 我不想涉及它们 我尝试在 NET Core S
  • 窗体最大化时自动缩放子控件

    有没有办法在最大化屏幕或更改分辨率时使 Windows 窗体上的所有内容自动缩放 我发现手动缩放它是正确的 但是当切换分辨率时我每次都必须更改它 this AutoScaleDimensions new System Drawing Siz
  • 如何在 C# 中播放在线资源中的 .mp3 文件?

    我的问题与此非常相似question https stackoverflow com questions 7556672 mp3 play from stream on c sharp 我有音乐网址 网址如http site com aud
  • 更改显示的 DPI 缩放大小使 Qt 应用程序的字体大小渲染得更大

    我使用 Qt 创建了一些 GUI 应用程序 我的 GUI 应用程序包含按钮和单选按钮等控件 当我运行应用程序时 按钮内的按钮和字体看起来正常 当我将显示器的 DPI 缩放大小从 100 更改为 150 或 200 时 无论分辨率如何 控件的
  • C++ 成员函数中的“if (!this)”有多糟糕?

    如果我遇到旧代码if this return 在应用程序中 这种风险有多严重 它是一个危险的定时炸弹 需要立即在应用程序范围内进行搜索和销毁工作 还是更像是一种可以悄悄留在原处的代码气味 我不打算writing当然 执行此操作的代码 相反

随机推荐

  • 【笔记-node】《imooc-nodejs入门到企业web开发中的应用》

    目录 课程名 备注 入门必学 nodejs入门到企业web开发中的应用 框架与工具 node js koa2 mysql打造前后端分离精品项目 旧岛 项目实战 20190317 20200720 imooc nodejs入门到企业web开发
  • DTO/VO/Entity等数据类型转换

    DTO VO Entity等数据类型转换 在web开发中 前端传递数据给后端时采用DTO类型 而存入数据库时则采用entity类型 这样的操作存在类型转换 如果我们一个一个的设值也就太麻烦了 我们可以采用spring提供的jar包来解决这样
  • 计算机 创新方法举例,列举列举五种创新的方法并加以举例说明

    一 简化模式 在研发新产品时 我们总会不自觉的想要在产品上增加新的特色或功能 导致产品使用起来越发复杂 这样的画蛇添足对产品来说是一种负担 我们要运用简化模式 主要是将产品中多余的属性移除 再增加新功能 例如 手机从键盘按键模式变成触屏的虚
  • mybatisPlus update更新部分字段

    第一种方式 其中 lambdaUpdateWrapper set 表示要更新的字段值 eq 则表示 WHERE 条件 public void updateEntity LambdaUpdateWrapper
  • 人工智能AI生成的艺术:从文本到图像、视频、3D建模

    继去年火遍全网的虚拟人之后 AI绘画又成了今年热议的科技话题 AI绘画就是 以文生图 打通了文字和图像的隔阂 只要输入一段文字描述 AI 就可以把用户脑海中想象的画面呈现出来 这是一种文字转图像 Text to image 特性的崭新交互方
  • 基于SpringBoot的在线教育平台系统

    基于SpringBoot Vue的线教育平台系统 前后端分离 开发语言 Java 数据库 MySQL 技术 SpringBoot Vue Mybaits Plus ELementUI 工具 IDEA Ecilpse Navicat Mave
  • 【专题5: 硬件设计】 之 【69.开关电源 之 如何计算buck电路占空比和电感的计算】

    嵌入式工程师成长之路 系列文章 总目录 系列文章总目录 希望本是无所谓有 无所谓无的 这正如脚下的路 其实地上本没有路 走的人多了 也便成了路 原创不易 文章会持续更新 欢迎微信扫码关注公众号 承接 小程序 嵌入式 PC端项目开发 联系作者
  • Apache Kafka Connect JNDI注入漏洞复现(CVE-2023-25194)

    1 产品简介 Kafka Connect是一种用于在Apache Kafka和其他系统之间可扩展且可靠地流式传输数据的工具 它使快速定义将大量数据移入和移出Kafka的连接器变得简单 Kafka Connect可以摄取整个数据库或从所有应用
  • STM32+SG90舵机详解(详细)

    上一次使用舵机只是草草了解 只大概知道是pwm控制的 这次又使用到了舵机 本以为复制上次代码就可以调试成功 没想到却弄了很久 我使用的是STM32f103c8t6 用的是定时器4 这个f1板子的定时器各个通道io口如下图所示 在开始之前我们
  • git push -u origin master

    1 错误描述 出错场景描述 github上创建远程仓库的时候选择添加README md文件 git bash连接远程库 然后执行push操作 出现下面的问题 git push u origin master To github com XX
  • Linux 下存放ssh信息的文件位置

    vi root ssh known hosts root prme stg dhcp1649 StorageJavaAuto cat root ssh known hosts prme stg188 eng vmware com 10 11
  • axure创建网页

    最近发现一个好玩的东西 就是axure了 学习操作了下 弄出了一个简单的搜狗页面还有登录界面 该有的交互也弄了些 感觉挺好玩的 也扒拉下生成了html 好好看看 代码可能有点长 你忍一下qwq
  • Ubuntu小技巧19--Kibana安装方法

    Ubuntu小技巧19 Kibana安装方法 Kibana 是一款开源的数据分析和可视化平台 它是 Elastic Stack 成员之一 设计用于和 Elasticsearch 协作 可以使用 Kibana 对 Elasticsearch
  • c++pointer踩坑记录 (std::move, shared_ptr)

    要实现的需求 拿到一个指向数据的void 指针 用这个指针替换旧对象数据 要求 不额外申请内存 我在这过程中搜过的问题 看的知识点 how to use enum in c use std move to pointer std vecto
  • ElasticSearch中字符串类型(Text和keyword)的选择

    ElasticSearch 5 0以后 字符串类型有重大变更 移除了string类型 string字段被拆分成两种新的数据类型 text和keyword text 会分词 然后进行索引 用于全文搜索 支持模糊 精确查询 不支持聚合 keyw
  • mysql深度剖析一(底层数据结构)

    衍变 二叉树 二叉查找树 容易形成链表 二叉平衡树 可以自动调整高度 但层数容易过高 多路平衡查找树即B树 层数控制了 但每个节点存有数据 导致每个磁盘页存不了多少索引 导致层数升高 传统加强版多路平衡查找树即B 树 每个磁盘页可以存更多索
  • 微服务 熔断示例_Istio作为何时不进行微服务的示例

    微服务 熔断示例 在过去的五年中 我在帮助企业进行云原生之旅方面投入了大量资金 现代化和提高团队 最终是组织 交付基于软件的技术的速度 很大程度上取决于其人员 流程和最终的技术决策 当应用程序体系结构的顶点已成为进行更改和 更快地进行 的瓶
  • 把ubuntu安装在U盘的教程之三:安装ubuntu系统在U盘中

    摘要 本文将详细讲解如何把U盘安装到U盘上 一 工具 1 一台电脑 2 一个U盘 用于安装ubuntu 注 要提前分好区 3 另一个U盘 制作好的ubuntu启动盘 二 安装ubuntu的图文教程 1 把两个U盘插进电脑 如果电脑有两个以上
  • linux运维基础视频教程免费分享!

    linux运维基础视频教程免费分享 linux运维即linux运维工程师 Linux是一套免费使用和自由传播的类Unix操作系统 是一个基于POSIX和UNIX的多用户 多任务 支持多线程和多CPU的操作系统 它能运行主要的UNIX工具软件
  • WPF的MVVM框架Stylet开发文档 17.设计模式支持

    17 设计模式支持 介绍 设计模式 或 设计时 是指当您的项目加载到 Visual Studio XAML 设计器或 Expression Blend 中时 您将看到 XAML 的渲染版本 大多数时候 设计者不会尝试评估您的任何绑定或为它们