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

Wpf*_*bie 42 c# wpf xaml mvvm

我可以像这样指定DataContext:

<Window ... >
    <Window.DataContext>
        <MainViewModel />
    </Window.DataContext>
    ...
</Window>
Run Code Online (Sandbox Code Playgroud)

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

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

我希望能够只指定一种类型ViewModel,所以如果我在{Binding}中拼错一个属性名称(或重命名属性后),我会得到设计时警告,或者我可以通过点击(在XAML中转到声明) )在{Binding PropertyName}内的属性名称上.

谢谢你无价的时光.

Tse*_*eng 45

如果你做自己动手的MVVM,这是一个棘手的部分.

您的选择,基本上:

使用依赖注入

您可以在Page/ Window的构造函数中注入ViewModel 并将其分配给它.

这有一些缺点.

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

ViewModel首先使用导航服务

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

这有点好,但仍然不允许你在XAML中实例化视图.大加号是,它允许您轻松地将参数传递给ViewModel(具有ViewModels实现INavigationAware属性的NavigatedTo方法,在实例化后调用并将参数传递给)

ViewModelLocator /附加属性/行为

使用这个,您将创建一个附加属性,您可以将其设置为true(即自动装配)或ViewModel类型(以更好地控制实例化的ViewModel)并查找并解析ViewModel并分配它.

它基本上给出了上面的所有优点以及View的实例化.

最后一个基本上是微软的MVVM框架"Prism"所做的事情(导航服务navigationService.Navigate("MyPage", myParameterForViewModel),DataContext实例化以及通过自动装配从XAML分配(在XAML中prism:ViewModelLocator.AutoWireViewModel="True").

话虽这么说,最好使用一个成熟的MVVM框架来完成这部分的布线(即使你决定不使用诸如BindableBase所述框架中所谓的基类或其他基类).

至于ViewModel的设计时ViewModel/auto-completition:

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

然后你可以通过它将它绑定到你的页面d:DataContext="{d:DesignInstance my:DesignTimeViewModel, IsDesignTimeCreatable=True}.注意d:在DataContext之前,这很重要.此DataContext仅在Designer(Visual Studio XAML Designer或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>
Run Code Online (Sandbox Code Playgroud)

如果对ViewModel使用Interfaces,那么创建设计实例的速度非常快,只需让Visual Studio实现所有Interface属性并为其提供一些默认值(对于属性,您可以在ViewModel中使用示例数据来验证绑定是否正常工作) .

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

  • 曾(Tseng),我在您的答案中添加了一个示例(带有DesignInstance标记扩展名)。有人请批准(我还没有足够的“权力”)。另外,我不必引用Blend程序集,而必须添加mc:Ignorable =“ d”进行编译。 (2认同)
  • DesignInstance 标记扩展解决了我的问题。谢谢你。标记为答案。 (2认同)