【问题标题】:How do I specify DataContext (ViewModel) type to get design-time binding checking in XAML editor without creating a ViewModel object? [duplicate]如何在不创建 ViewModel 对象的情况下指定 DataContext (ViewModel) 类型以在 XAML 编辑器中进行设计时绑定检查? [复制]
【发布时间】:2015-06-06 14:15:09
【问题描述】:

我可以像这样指定 DataContext:

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

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

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

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

感谢您宝贵的时间。

【问题讨论】:

    标签: c# wpf xaml mvvm


    【解决方案1】:

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

    你的选择,基本上:

    使用依赖注入

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

    但这有一些缺点。

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

    带导航服务的 ViewModel 优先

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

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

    ViewModelLocator / 附加属性/行为

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

    它基本上提供了上述所有优点以及实例化表单视图。

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

    话虽如此,最好使用成熟的 MVVM 框架来完成这部分接线(即使您决定不使用基类,例如 BindableBase 或在所述框架中调用的任何内容)。

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

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

    然后您可以通过d:DataContext="{d:DesignInstance my:DesignTimeViewModel, IsDesignTimeCreatable=True} 将其绑定到您的页面中。注意 DataContext 之前的d:,这很重要。此 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 使用接口,则创建设计实例非常快,只需让 Visual Studio 实现所有接口属性并为其提供一些默认值(对于属性,您可以在 ViewModel 中有示例数据来验证绑定正常工作)。

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

    【讨论】:

    • 曾,谢谢您的回复。使用“使用依赖注入”选项将不会进行设计时绑定检查,即在 XAML 编辑器中,我将收到“由于未知数据上下文而无法解析符号 XXX”警告。此外,我将无法单击“{Binding PropertyName}”中的属性名称并自动跳转到属性声明。
    • Tseng,我在您的答案中添加了一个示例(带有 DesignInstance 标记扩展)。请有人批准(我还没有足够的“权力”)。另外,我不必引用 Blend 程序集,我必须添加 mc:Ignorable="d" 才能使其编译。
    • DesignInstance 标记扩展解决了我的问题。谢谢你。标记为答案。
    • 感谢您的解决方案。 IsDesignTimeCreatable=True
    猜你喜欢
    • 2012-10-14
    • 1970-01-01
    • 2015-10-22
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多