Лучший подход к настройке видимости в 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>
но, может быть, я совершенно неправильно. но ваш фактический вопрос пусть так много места для интерпретации