如何使用DataContext属性在XAML中的窗口上设置ViewModel?


96

这个问题几乎说明了一切。

我有一个窗口,并尝试使用完整的名称空间将DataContext设置为ViewModel,但是我似乎做错了。

<Window x:Class="BuildAssistantUI.BuildAssistantWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="BuildAssistantUI.ViewModels.MainViewModel">

跟进Mike Nakis之后,我试图手动创建ViewModel并订阅其中的事件,却发现该框架正在创建另一个ViewModel。因此,我所订阅的viewModel不是附加到视图的那个。
jlady

这是否意味着除了您自己实例化视图模型之外,您以其他方式指定了视图模型的类型?要求构造函数参数的视图模型的第二个优点是,框架要么无法实例化它们,要么必须传递这些参数的默认值,在这种情况下,您可以轻松地通过框架检测实例化。
Mike Nakis

XAML设计器可能还需要能够实例化视图模型,但是该设计器对我从来没有任何用处,(它只会引起问题),因此我不使用它,因此我个人并不关心这种使用情况。
Mike Nakis

Answers:


112

除了其他人提供的解决方案(既好又正确)之外,还有一种方法可以在XAML中指定ViewModel,但仍将特定的ViewModel与View分开。当您要编写隔离的测试用例时,将它们分开很有用。

在App.xaml中:

<Application
    x:Class="BuildAssistantUI.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:BuildAssistantUI.ViewModels"
    StartupUri="MainWindow.xaml"
    >
    <Application.Resources>
        <local:MainViewModel x:Key="MainViewModel" />
    </Application.Resources>
</Application>

在MainWindow.xaml中:

<Window x:Class="BuildAssistantUI.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{StaticResource MainViewModel}"
    />

哦,哇...谢谢。我已经将此标记为“已回答”,但是非常感谢您的添加。将使用它。
尼古拉斯

@Nicholas:另一个答案非常适合该问题,因此我同意您的决定
Merlyn Morgan-Graham

8
请注意,此方法对MainWindow的每个实例都使用相同的ViewModel实例。如果窗口是这种情况下的单实例,那很好,但是如果您正在显示窗口的多个实例(例如,在MDI或选项卡式应用程序的情况下),那不是很好。
乔什(Josh)

1
实际上,Josh的答案更好,因为它为您提供了DataContext的类型安全性。因此,您可以直接绑定到DataContext,而不必担心输入某些属性名称/路径。
Josh M.

149

试试这个吧。

<Window x:Class="BuildAssistantUI.BuildAssistantWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:VM="clr-namespace:BuildAssistantUI.ViewModels">
    <Window.DataContext>
        <VM:MainViewModel />
    </Window.DataContext>
</Window>

3
我最喜欢这个选项。如果VM仅用于MainWindow,则看起来更干净。
Andrew Grothe

13
有没有一种方法可以使用Window元素上的属性来设置数据上下文,例如DataContext="VM:MainWindowViewModel"
奥利弗

这是正确的方法!
JavierIEH 2015年

我并不完全理解为什么一种方法比另一种更好。另外,与我看到某些人使用“动态资源”的方式相比,我没有完全看到这两种方式的差异。这是什么?
Travis Tubbs

1
@Oliver您必须实现MarkupExtension,但从未在VM上实现,但是您可以使用转换器来实现它,以确保仅存在一个转换器实例,并通过xaml直接调用它="{converters:SomethingConverter}",暗示xmlns:converters在转换器命名空间指向。 public abstract class BaseValueConverter<T> : MarkupExtension, IValueConverter where T : class, new() { private static T _converter; public override object ProvideValue(IServiceProvider serviceProvider) { return _converter ?? (_converter = new T()); } }
Whazz

11

您需要实例化MainViewModel并将其设置为datacontext。在您的语句中,只需将其视为字符串值即可。

     <Window x:Class="BuildAssistantUI.BuildAssistantWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:BuildAssistantUI.ViewModels">
      <Window.DataContext>
        <local:MainViewModel/>
      </Window.DataContext>

谢谢,我认为它正在这样做。
尼古拉斯

3

您可能要尝试 Catel。它允许您定义一个DataWindow类(而不是Window),并且该类自动为您创建视图模型。这样,您可以像在原始文章中一样使用ViewModel的声明,并且仍将创建视图模型并将其设置为DataContext。

请参阅本文的示例。


2

还有一种指定viewmodel的方法:

using Wpf = System.Windows;

public partial class App : Wpf.Application //your skeleton app already has this.
{
    protected override void OnStartup( Wpf.StartupEventArgs e ) //you need to add this.
    {
        base.OnStartup( e );
        MainWindow = new MainView();
        MainWindow.DataContext = new MainViewModel( e.Args );
        MainWindow.Show();
    }
}

<Rant>

先前提出的所有解决方案都要求MainViewModel必须具有无参数构造函数。

微软给人的印象是可以使用无参数构造函数来构建系统。如果您也对此印象深刻,请继续使用其他一些解决方案。

对于那些知道构造函数必须具有参数的对象,因此对象的实例化不能留在魔术框架的手中,指定视图模型的正确方法是上面显示的方法。

</ Rant>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.