Как иметь несколько представлений с использованием одной и той же модели представления в MVVM?

Я новичок как в WPF, так и в MVVM, и при попытке установить DataContext на один и тот же экземпляр моей ViewModel в двух разных представлениях возникла проблема.

Это произошло потому, что:

<Window.DataContext>
    <local:ViewModel/>
</Window.DataContext>

создаст новый экземпляр модели представления для каждого представления.

Чтобы обойти это, я решил создать класс, в котором хранятся статические экземпляры каждой модели ViewModel, которую я использовал. Затем в файле cs каждого представления я бы установил для DataContext соответствующую ViewModel из этого статического класса.

Это работает, но не кажется лучшей идеей для больших программ, где могут потребоваться несколько экземпляров ViewModel одновременно.

Каковы лучшие подходы к этой проблеме? Существуют ли разумные способы иметь несколько представлений с использованием одного и того же экземпляра ViewModel?

Или это плохая практика - следует ли мне разрабатывать программу с одним представлением для каждой модели представления?

У меня нет для тебя ответа. Я никогда не сталкивался с описанной вами ситуацией, когда несколько представлений назначали бы одну модель представления. Не могли бы вы сказать, что пытаетесь сделать? Мне просто интересно.

Ladislav Ondris 26.07.2018 12:59

Caliburn.Micro предлагает несколько представлений для одной модели представления через свойство "cal: View.Context". Может быть, вы можете посмотреть в их исходном коде, как это технически достигается.

Sven Bardos 26.07.2018 13:07

@LadislavOndris Итак, я создал простую игру в крестики-нолики, ViewModel содержит экземпляр класса Game, содержащий всю информацию, необходимую для игры, и у меня есть два отдельных представления: одно для игрового поля (сетка кнопок 3x3) и один для информации об игре (чей ход, количество побед и т. д.)

Alfie 26.07.2018 13:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
3
8 449
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Ответ принят как подходящий

Вы можете создать экземпляр этой модели представления в App.xaml, чтобы она была доступна для всего приложения.

<Application.Resources>
    <local:ViewModel x:Key = "sharedViewModel" />
</Application.Resources>

Затем в ваших представлениях, когда вы хотите использовать этот текст данных, вы делаете следующее ...

DataContext = "{StaticResource sharedViewModel}"

Простой и легкий, а также один из рекомендуемых подходов - это реализация ViewModelLocator.

Идея определила все модели ViewModel в классе ViewModelLocator и получила доступ к ViewModel везде, где это необходимо. Использование одной и той же модели представления в другом представлении не будет проблемой.

    public class ViewModelLocator
{
         private MainWindowViewModel mainWindowViewModel;
  public MainWindowViewModel MainWindowViewModel
    {
        get
        {
            if (mainWindowViewModel == null)
                mainWindowViewModel = new MainWindowViewModel();

            return mainWindowViewModel;
        }
    }
    private DataFactoryViewModel dataFactoryViewModel;
 public DataFactoryViewModel DataFactoryViewModel
    {
        get
        {
            if (dataFactoryViewModel == null)
                dataFactoryViewModel = new DataFactoryViewModel();

            return dataFactoryViewModel;
        }
    }
}

App.xaml

    xmlns:core = "clr-namespace:MyViewModelLocatorNamespace"

<Application.Resources>
    <core:ViewModelLocator x:Key = "ViewModelLocator" />
</Application.Resources>

Применение

<Window ...
  DataContext = "{Binding Path=MainWindowViewModel, Source = {StaticResource ViewModelLocator}}">

см .: коды Итак, вопрос скопированы оттуда .. так как я не могу скопировать коды из моего проекта ..

Каковы на самом деле две возможности возврата свойства MainViewModel?

Alfie 26.07.2018 14:42

@Alfie, извини, я не совсем понимаю твой вопрос. Я говорил, что вместо того, чтобы определять каждую ViewModels как ресурсы в App.Xaml, вы можете определить их в классе и использовать класс в привязках. это также рекомендуемый подход. см. обновленный код ..

WPFUser 26.07.2018 14:51

Этот ответ настолько недооценен, но настолько прост и эффективен, спасибо

Juanca 17.03.2021 01:50

У меня был тот же вопрос, и я не мог найти хорошего ответа. Поразмыслив над этим некоторое время, я пришел к выводу, что в большинстве случаев лучше всего создать сопоставление «один к одному» между моделью представления и представлением. Поэтому в этой ситуации я бы создал две отдельные модели представления, которые наследуются от базовой модели представления. Таким образом, вы можете поместить все, что является общим в базовой модели представления, и добавить любые поля или методы, которые могут отличаться от более конкретной модели представления. Если модели представления действительно эквивалентны, вы можете спросить себя, почему у вас вообще два отдельных представления. Вы можете объединить их в одно представление. Возможно, вам нужно иметь два отдельных представления, но это просто необходимо учитывать.

Я использую структуру призмы, а также искал решение использовать одну модель представления для многих (дочерних) представлений. В призме есть два возможных решения:

  1. Определите модель просмотра как singleton (запах кода) или
  2. Использование RegionContext (полное описание см. В документации по призме)

Согласно документу призмы, мое решение выглядит так.

В загрузчике призмы:

Container.RegisterTypeForNavigation<MyView>("MyView");

В модели просмотра:

private void DisplayView(string viewName)
{
    RegionManager.Regions["ContentRegion"].Context = this;  // set viewmodel
    RegionManager.RequestNavigate("ContentRegion", viewName);
}

В коде каждого представления:

public MyView()
{
    InitializeComponent();
    ObservableObject<object> viewRegionContext = RegionContext.GetObservableContext(this);
    viewRegionContext.PropertyChanged += this.ViewRegionContext_OnPropertyChangedEvent;
}

private void ViewRegionContext_OnPropertyChangedEvent(object sender, PropertyChangedEventArgs args)
{
    if (args.PropertyName == "Value")
    {
        var context = (ObservableObject<object>)sender;
        DataContext = context.Value;  // get viewmodel as DataContext
    }
}

Другие вопросы по теме