MVVM + Реализация View определенных функций, вызываемых ViewModel - PullRequest
2 голосов
/ 19 апреля 2011

вот моя «проблема», которую я хочу решить:

У меня есть много специальных функций «Только для просмотра», например:

  • Изменение ResourcesDictionary представления во время выполнения (для изменения скинов с черного на синий и т. Д.)
  • Сохранение и восстановление Просмотр определенных настроек, таких как размер вида или свойства сетки, заданные пользователем
  • ...

Все эти функциональные возможности не имеют ничего общего с ViewModel, поскольку они действительно специфичны для представления и могут соответствовать только одному клиенту (View) ViewModel (в случае, если ViewModel имеет более одного клиента). Приведенные выше примеры - это только две из большого количества функций, которые я хочу реализовать, поэтому мне нужно более общее решение вместо решений, которые соответствуют только этим двум примерам.

Размышляя о решении, я пришел к двум следующим подходам

  • Создать ViewBase, который наследуется от DependancyObject. Мне не нравится это решение, потому что оно каким-то образом нарушает идею шаблона MVVM, где View не имеет кода. И чтобы вызвать эти методы, мне как-то нужно сослаться на View в моей ViewModel, что также отрицает идею разделения проблем.
  • Создание интерфейса IView. Как грязно, как первый подход. В каждом представлении должен быть реализован IView, и здесь есть код. Также ViewModel нужно «как-то» знать реализацию IView для вызова его методов
  • Свяжите свойства ViewModel с триггерами, поведением, командами представления. Этот подход кажется лучшим, но я думаю, что я ограничусь очень быстрым использованием, потому что некоторые функции могут не работать с этим подходом. Например, просто привязка resourceDictionary к представлению может не работать, поскольку для правильного отображения новых ресурсов необходимо объединение. Опять же ... У меня есть представление только определенных функций / информации (например, определение ресурсов) в ViewModel, но только конкретный клиент ViewModel использует это свойство.

Если бы кто-то из вас уже имел ту же проблему и получил умное / плавное (и в основном общее;)) решение для моей проблемы, это было бы замечательно.

Спасибо

Ответы [ 4 ]

1 голос
/ 21 декабря 2011

Я давно принял способ думать, что Шаблоны были созданы для Человека, а не Человек для шаблонов.Довольно часто вы видите ситуацию, когда MVVM не подходит, и чтобы ее решить, очень умные люди придумали способы обойти это, сохраняя при этом чистый MVVM-вид.

Однако, если вы подписались на мою школу мысли или просто хотите сохранить простоту, другой способ - позволить ViewModel ссылаться на представление;через интерфейс, конечно, или это просто ужасная практика программирования.Теперь возникает вопрос, как получить представление в viewmodel?

простейшим способом было бы сделать это в событии dataContextChanged представления.Однако, если вы хотите попробовать что-то другое, как насчет использования присоединенного свойства или свойства зависимости, чтобы внедрить представление в модель представления?

Я успешно использовал эту технику в ряде проектов WPF и не чувствую себя грязным или каким-то скомпрометированным.Я называю это MiVVM или модель с интерфейсом для просмотра ViewModel .

Шаблон прост.Ваш Usercontrol должен иметь интерфейс, назовите его IMyView.Затем в ViewModel у вас есть свойство с сеттером типа IMyView, скажем,

public IMyView InjectedView { set { _injectedView = value; } }

Затем в представлении вы создаете свойство зависимостей с именем This

public MyUserControl : IMyView
{
    public static readonly DependencyProperty ThisProperty = 
         DependencyProperty.Register("This", typeof(IMyView), typeof(MyUserControl)); 

    public MyUserControl() 
    {
       SetValue(ThisProperty, this);
    } 
    public IMyView This { get { return GetValue(ThisProperty); } set { /* do nothing */ } } 
}

наконец, в Xaml вы можете добавить представление непосредственно в ViewModel, используя привязку

<MyUserControl This="{Binding InjectedView, Mode=OneWayToSource}"/>

Попробуйте!Я использовал этот шаблон много раз, и вы получаете интерфейс к представлению, внедренному один раз при запуске.Это означает, что вы поддерживаете разделение (Viewmodel можно протестировать, так как IView можно смоделировать), но вы обошли отсутствие поддержки связывания во многих сторонних элементах управления.Плюс, это быстро.Знаете ли вы, связывание использует отражение?

Существует демонстрационный проект, демонстрирующий этот шаблон на этой ссылке в блоге .Я бы рекомендовал опробовать реализацию MiVVM с присоединенным свойством, если вы используете сторонний элемент управления, который вы не можете изменить.

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

1 голос
/ 21 апреля 2011

Самый простой способ сделать это без введения связи между View и ViewModel - это использовать Messenger (также называемый в некоторых средах Mediator).ViewModel просто передает сообщение «сменить тему», и View подписывается на это сообщение.Используя класс Messenger из MVVM Light, вы можете сделать что-то в этом духе:

Определение сообщения

public class ThemeChangeMessage
{
    private readonly string _themeName;
    public ThemeChangeMessage(string themeName)
    {
        _themeName = themeName;
    }

    public string ThemeName { get { return _themeName; } }
}

ViewModel

Messenger.Default.Send(new ThemeChangeMessage("TheNewTheme");

Просмотреть код позади

public MyView()
{
    InitializeComponent();
    Messenger.Defaut.Register<ThemeChangeMessage>(ChangeTheme);
}

private void ChangeTheme(ThemeChangeMessage msg)
{
    ApplyNewTheme(msg.ThemeName);
}
0 голосов
/ 21 апреля 2011

Я согласен, что просмотр определенных функций должен оставаться в представлении (сохранить и восстановить размер окна, установить фокус на определенный элемент управления и т. Д.).

Но я не согласен с тем, что введение интерфейса IView является «грязным».Это общий шаблон проектирования, называемый Разделенный интерфейс , который описан в книге Мартина Фаулера «Шаблоны архитектуры корпоративных приложений».Кроме того, выделение кода не является «злом», поскольку код относится к определенным функциям View.К сожалению, это распространенное недопонимание в сообществе MVVM.

Если вы измените подход интерфейса IView, то вы можете найти WPF Application Framework (WAF) интересно.Это решает наши проблемы через этот интерфейс.Вы увидите это в примерах приложений.

0 голосов
/ 20 апреля 2011

Когда вы сказали

У меня есть много специфических функций «Только для просмотра», например:

, что заставляет меня думать, что вы смешиваете «Что» и«Как».Я объясню, что я имею в виду под этим.

Каковы требования вашего приложения:

  • Изменение цвета обложки приложения
  • Сохранение и восстановление
    • Размер
    • Свойства сетки

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

public class SettingsViewModel
{
  public Color Skin { get;set;}
  public Size ViewSize {get;set;}
  public GridProperties GridProperties {get;set;}

  public void Save() {//TODO:Add code}
  public void Restore() {//TODO:Add code}
}

ваш вид будет привязан к этому ViewModel и реализует «как».

Если вы создаете веб-приложение, то как будетViewModel и создать HTML.Если вы используете WPF, вы привязываетесь к этим свойствам в XAML и создаете свой пользовательский интерфейс (который может заставить вас отключить ResourceDictionaries и т. Д.)и ViewModel.В чистом виде ViewModel не должен знать ничего о View, но View должен знать все, что ему нужно знать о ViewModel.

В этом весь смысл разделения интересов.

Ответы на ваши "решения":

  • Ваш первый вариант нарушает принципы MVVM, читали ли вы эту статью?
  • Я верю эта статья поможет вам прийти к соглашению с выбором вида на основе ViewModel.
  • Я не знаю, с какими "ограничениями" вы столкнетесь, но WPF достаточно надежен и будетбыть решения доступны.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...