Лучший подход к настройке видимости в MVVM

в своем View У меня есть три объекта, один из которых виден в любой момент времени. В моем Model У меня есть перечисление для представления трех состояний.

как я должен реализовать мой ViewModel?

a) создайте логическое значение для видимости каждого объекта и свяжите каждый объект с этим (с помощью преобразователя bool->visibility).

b) привязка к перечислению с уникальным преобразователем для каждого объекта.

c) привязка к перечислению с помощью одного преобразователя, который принимает параметр.

d) используйте визуальный диспетчер состояний с логическими фреймами ключей и управляйте состоянием из виртуальной машины с помощью вложенного свойства.

e) привязать к перечислению VM из кода позади и установить видимость через код.

f)?

Я серьезно надеюсь, что ответ f) (т. е. очевидный выбор, который ускользает от меня), потому что я не очень доволен a) через e).

мысли приветствуются и ценятся.

3 ответов


лучший подход в MVVM не обязательно означает легко. Мне нравятся следующие подходы:

a) создайте логическое значение для видимости каждого объекта и свяжите каждый объект с этим (с помощью преобразователя bool->visibility).

этот метод является наиболее интуитивным и классическим для настройки видимости для Control.

b) привязка к перечислению с уникальным преобразователем для каждого объекта.

c) привязка к перечислению с помощью одного преобразователя, который принимает параметр.

в случае преобразователя, Enum лучше держать не в Model и в сторону View. Потому что проблема решается в сторону представления, что вполне логично и здесь хранить структуру данных. В принципе, это не критично.

пример:

public sealed class InvertableBooleanToVisibilityConverter : IValueConverter
{
    enum Parameters
    {
        Normal, 
        Inverted
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var boolValue = (bool)value;
        var direction = (Parameters)Enum.Parse(typeof(Parameters), (string)parameter);

        if (direction == Parameters.Inverted)
            return !boolValue ? Visibility.Visible : Visibility.Collapsed;

        return boolValue ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return DependencyProperty.UnsetValue;
    }
}

несколько комментариев о других подходах:

d) используйте визуальный диспетчер состояний с логическими фреймами ключей и управляйте состоянием из виртуальной машины с помощью вложенного свойства.

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

e) привязать к перечислению VM из кода позади и установить видимость через код.

Code-behind в этом случае не оправдан, когда вы можете решить проблема с использованием обычных средств в MVVM (привязки, преобразователи и т. д.). Я думаю, в этом случае это не было бы нарушением принципа MVVM, если бы выбирался элемент Visibility не участвует бизнес-логика, например, может прийти установка видимости, нажав CheckBox, ToggleButton, etc.


c) Bind to the enum, with a single converter that takes a parameter.

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

e) Bind to the VM enum from code behind, and set visibility thru code.

плохая идея. Это плохая практика.


В дополнение к моему комментарию. когда у меня есть задача показать различное содержимое в представлении в зависимости от разных объектов. я использую большую часть времени contentcontrol и datatemplates.

  <ContentControl Content="{Binding MyEnumObject}"/>

Теперь в моей viewmodel у меня есть все типы объектов diffrent и установите объект, который я хочу, чтобы мое свойство привязывалось к представлению.

   private Blup _blup; //eg. is wanted when enum in model = 1

   public object MyEnumObject {get;set;}


   //set the content in your viewmodel 
   this.MyEnumObject = _blup;

Теперь вам просто нужен datatemplate для визуализации ваших объектов

   <DataTemplate DataType="{x:Type local:Blup}">
    <view:MyBlupViewControl/>
   </DataTemplate>

но, может быть, я совершенно неправильно. но ваш фактический вопрос пусть так много места для интерпретации