Як встановити ViewModel у вікні в XAML за допомогою властивості DataContext?


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">

Відповіді:


112

На додаток до рішення, яке надали інші люди (яке є добрим і правильним), існує спосіб вказати ViewModel у XAML, але все одно відокремити конкретний 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: Інша відповідь ідеально підходить для запитання, тому я погоджуюся з вашим рішенням
Мерлін Морган-Грем

8
Тільки майте на увазі, що цей підхід використовує той самий екземпляр ViewModel для кожного екземпляра MainWindow. Це чудово, якщо вікно є єдиним екземпляром, як передбачається у цьому випадку, але не якщо ви показуєте кілька екземплярів вікна, наприклад, у випадку MDI або програми з вкладками.
Джош

1
Насправді відповідь Джоша є кращою, оскільки вона забезпечує вам безпеку типу в DataContext. Отже, ви можете прив’язатись безпосередньо до DataContext, не турбуючись про введення певного імені / шляху властивості.
Джош М.

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
Цей варіант мені найбільше подобається. Здається чистішим, якщо віртуальна машина використовується лише для MainWindow.
Andrew Grothe,

13
Чи є спосіб встановити контекст даних, використовуючи атрибут Windowелемента, наприклад DataContext="VM:MainWindowViewModel"?
Олівер

Це правильний спосіб!
JavierIEH

Я не до кінця розумію, чому один шлях кращий за інший. Крім того, я не бачу абсолютно різниці в жодному з цих способів у порівнянні з тим, як я бачив, як деякі люди використовують "Динамічний ресурс". Що це?
Тревіс Таббс

1
@Oliver вам потрібно було б реалізувати MarkupExtension, ніколи цього не робив на віртуальних машинах, але ви можете зробити це за допомогою перетворювачів, щоб переконатися, що присутній лише один екземпляр перетворювача, і викликати його прямо з 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.

Див. Цю статтю для прикладу.


1

Існує також такий спосіб вказати модель перегляду:

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потрібно мати безпараметричний конструктор.

У Microsoft складається враження, що системи можна будувати за допомогою безпараметричних конструкторів. Якщо у вас також склалося таке враження, використовуйте інші рішення.

Для тих, хто знає, що конструктори повинні мати параметри, і тому створення екземплярів об'єктів не може залишатися в руках магічних фреймворків, правильний спосіб вказати модель перегляду тієї, яку я показав вище.

</Rant>

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.