c# - 如何在不创建 ViewModel 对象的情况下指定 DataContext (ViewModel) 类型以在 XAML 编辑器中进行设计时绑定(bind)检查?

标签 c# wpf xaml mvvm

<分区>

我可以像这样指定 DataContext:

<Window ... >
    <Window.DataContext>
        <MainViewModel />
    </Window.DataContext>
    ...
</Window>

在这种情况下,WPF 将创建一个 MainViewModel 类型的对象并将其分配给窗口的 DataContext 属性(这发生在 Window 的 InitializeComponent() 方法中)。

但是如果我的 ViewModel 没有默认构造函数怎么办。或者如果我想在执行 Window.InitializeComponent() 之后初始化 ViewModel 并将其分配给 DataContext 怎么办(在 Window 的构造函数内或从实例化窗口的相同代码) - 在这种情况下 WPF 创建一个 ViewModel (在 InitializeComponent() 内),将它分配给窗口的 DataContext,然后我用另一个 ViewModel 实例覆盖它(我担心这里不必要的对象实例化)。

我希望能够仅指定一种类型的 ViewModel,因此如果我在 {Binding} 中拼错属性名称(或重命名属性之后),我会收到设计时警告,或者我可以通过单击(在 XAML 中){Binding PropertyName} 中的属性名称来转到声明。

最佳答案

如果您自己动手做 MVVM,那将是棘手的部分。

你的选择,基本上:

使用依赖注入(inject)

您可以在 Page/Window 的构造函数中注入(inject) ViewModel 并在其中分配它。

虽然这有一些缺点。

  • 更难使用设计时 View 模型
  • 无法再从 XAML 实例化 View

ViewModel First with Navigation Service

您将解析您的 ViewModel 并通过导航服务进行所有导航。在您的 ViewModel 中,您传递一个 INavigationService。您可以使用 ViewModel 类型导航到 View 。在它内部通过依赖注入(inject)实例化 ViewModel,然后实例化 View (基于命名约定或通过 DI 配置)

这要好一些,但仍然不允许您在 XAML 中实例化 View 。最大的优点是,它允许您轻松地将参数传递给 ViewModel(让 ViewModels 使用 NavigatedTo 方法实现 INavigationAware 属性,该方法在实例化并将参数传递给之后调用)

ViewModelLocator/附加属性/行为

有了这个,您将创建一个附加属性,您可以将其设置为 true(即 Autowiring )或 ViewModel 类型(以更好地控制实例化的 ViewModel)以及查找和解析 ViewModel 并分配它。

它基本上提供了上述所有优点以及 View 的实例化。

最后一个基本上是 Microsoft 的 MVVM 框架“Prism”所做的(导航服务 navigationService.Navigate("MyPage", myParameterForViewModel),通过 Autowiring 从 XAML 实例化和分配 DataContext(在 XAML 中:棱镜:ViewModelLocator.AutoWireViewModel="True").

也就是说,最好使用成熟的 MVVM 框架来完成这部分布线(即使您决定不使用基类,例如 BindableBase 或在所述框架中调用的任何内容).

至于设计时 ViewModel/ViewModel 的自动完成:

您可以使用 Blend 的设计时属性来执行此操作。您需要先添加 Blend 程序集引用。然后您可以将 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 命名空间添加到您的页面/ View 中。

然后您可以通过 d:DataContext="{d:DesignInstance my:DesignTimeViewModel, IsDesignTimeCreatable=True} 将其绑定(bind)到您的页面。注意 d: 之前DataContext,这很重要。这个 DataContext 只会在设计器中使用(Visual Studio XAML 设计器或在 Blend 中)。这是为了防止干扰正常的 DataContext(没有前缀)。

例子:

<Window x:Class="WpfApplication1.Window2"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:myApp="clr-namespace:WpfApplication1"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DataContext="{d:DesignInstance myApp:Window2ViewModel, IsDesignTimeCreatable=True}">
    <Grid>
        <TextBlock Text ="{Binding Test}"/>
    </Grid>
</Window>

如果您为 ViewModel 使用接口(interface),创 build 计实例的速度非常快,只需让 Visual Studio 实现所有接口(interface)属性并为其提供一些默认值(对于属性,以便您的 ViewModel 中有示例数据来验证绑定(bind)正常工作)。

这需要您创建单独的设计时 ViewModel 和您的实际 ViewModel,这并不像听起来那么糟糕。这使您的 UI 设计师有机会使用它,即使真正的 ViewModel 尚未完成/实现。

关于c# - 如何在不创建 ViewModel 对象的情况下指定 DataContext (ViewModel) 类型以在 XAML 编辑器中进行设计时绑定(bind)检查?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29399157/

相关文章:

c# - 目录的 GetTempFileName 函数?

wpf - MVVM - 控件与 View

css - TargetType 上的 WPF 样式选择器指定嵌套的目标类型

c# - 在 C# 中使用参数启动新线程

c# - 未调用 WebApi v2 ExceptionHandler

c# - Active Directory 联合身份验证服务是否支持 OpenID Connect 声明提供程序

c# - 如何处理应用程序范围内可访问的字符串?

c# - XAML 自动类型转换

xaml - 右对齐 ListBox 中的内容

c# - 将 "Android.Views.ViewGroup"添加到 Xamarin XAML 页面