MVVM связывает ортогональные аспекты в представлениях, например Настройки приложения - PullRequest
5 голосов
/ 12 мая 2010

У меня есть приложение, которое я разрабатываю с использованием WPF \ Prism \ MVVM. Все идет хорошо, и у меня есть несколько приятных реализаций MVVM. Тем не менее, в некоторых моих представлениях я хотел бы иметь возможность привязать настройки приложения, например, когда пользователь перезагружает приложение, флажок для автоматической прокрутки сетки должен быть установлен в том состоянии, в котором он был в последний раз, когда пользователь использовал приложение.

Мое представление должно привязываться к чему-то, что содержит состояние настройки «автопрокрутка». Я мог бы поместить это в модель представления, но настройки приложений являются ортогональными к цели модели представления. Параметр «автопрокрутка» управляет аспектом вида. Этот параметр является только примером. Их будет довольно много, и мои модели представлений со свойствами, представляющими настройки приложения (чтобы я мог их связать), будут казаться совершенно отвратительными.

Кажется, что одна модель-представление для каждого вида является правильной ...

Какая здесь лучшая \ обычная практика?

  • Брызги моих моделей просмотра с настройками приложения?
  • У вас есть несколько моделей представлений для каждого вида, чтобы настройки можно было представлять самостоятельно?
  • Разделить представления, чтобы элементы управления могли связываться с ApplicationSettingsViewModel? = слишком много просмотров?
  • Что-то еще?

Редактировать 1

Чтобы добавить немного контекста, я разрабатываю пользовательский интерфейс с динамическим интерфейсом с вкладками. На каждой вкладке будет размещен один виджет, и существует множество виджетов. Каждый виджет представляет собой композицию отдельных представлений Prism. Некоторые виды распространены среди виджетов, например представление выбора файлов. Хотя каждый виджет состоит из нескольких представлений, концептуально виджет имеет один набор пользовательских настроек, например последний выбранный файл, включена автопрокрутка и т. д. Их необходимо сохранить и извлечь \ применить при повторном запуске приложения и повторном создании представлений виджетов.

Мой вопрос сосредоточен на том факте, что концептуально виджет имеет единый набор пользовательских настроек, который находится под прямым углом к ​​факту, что виджет состоит из множества представлений. Каждое представление в виджете имеет свою собственную модель представления (которая работает красиво и логично), но если я буду придерживаться одной модели представления для каждого представления, мне придется разбить каждую модель представления с помощью пользовательских настроек поддерживаемых свойств (чтобы я мог связать данные ).

Отдельная модель вида для каждого вида здесь не звучит, если мне придется разбрызгивать каждую модель вида с помощью пользовательских настроек.

Ответы [ 3 ]

2 голосов
/ 15 мая 2010

Основная проблема здесь заключается в использовании Prism для создания вложенных представлений для создания виджета - вложенные представления слишком мелкие.

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

Теперь, когда у нас есть одно представление: WidgetView (сделанное из пользовательских элементов управления), мы можем связать это представление с одной моделью представления: WidgetViewModel. Обработка настроек для вида виджета затем обрабатывается путем составления нескольких видов моделей. Просто поместите свойство в WidgetViewModel, которое предоставляет WidgetSettingsViewModel. Пользовательские элементы управления привязывают WidgetViewModel для взаимодействия с базовой моделью, но привязывают к WidgetSettingsViewModel для настроек виджетов.

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

1 голос
/ 13 мая 2010

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

 <CheckBox IsChecked="{Binding SomeSetting,
                       Source={x:Static myAppProperties:Settings.Default}}" />

Предполагается, что вы используете функцию настройки приложения System.Configuration, как показано в файлах ".settings" Visual Studio. Если вы используете какой-то другой механизм для сохранения своих настроек, этот метод все равно будет работать: просто выставьте настройки своего пользователя и приложения на статический объект и привяжите к нему.

Если у вас есть диалоговое окно «Параметры», в котором есть множество параметров приложения, вы можете упростить задачу, используя объект «Параметры» в качестве своего DataContext:

<DockPanel DataContext="{Binding Source={x:Static myAppProperties:Settings.Default}}">
  ...
  <CheckBox IsChecked="{Binding SomeSetting}" />
  ...

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

Я также нашел полезным связать настройки со свойствами своих объектов, не относящимися к пользовательскому интерфейсу, чтобы объекты получали события PropertyChangedCallback при изменении настроек приложения, делая их обновление простым и избегая загромождения моего кода множеством ненужных регистраций событий. 1011 *

0 голосов
/ 13 мая 2010

Ах, ваша редакция проясняет все достаточно, чтобы оправдать новый ответ. Вот оно:

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

В вашем случае у вас есть набор настроек, которые вы хотите связать с каждой комбинацией {пользователь, виджет}. Эта коллекция настроек должна быть сохранена и доступна в каждом из ваших представлений. Концептуально это отдельный объект модели: это не виджет, это не пользователь и он не зависит от вида. Называете ли вы это «моделью представления» или просто «моделью», это, прежде всего, вопрос терминологии. Как бы вы ни хотели его классифицировать, давайте назовем сам объект UserWidgetSettings.

Где-то у вас будет резервное хранилище, в котором вы сохраните объекты UserWidgetSettings. Это может быть в локальном файле, в реестре или в той же базе данных, где хранятся ваши объекты User и Widget. Для обсуждения предположим, что вы храните их отдельно от объектов User и Widget, и у вас есть класс, который сохраняет их:

public class UserWidgetSettings : DependencyObject // or INotifyPropertyChanged
{
  public bool AutoScroll { get { return (bool)GetValue(AutoScrollProperty); } set { SetValue(AutoScrollPropery, value); } }
  public static readonly DependencyProperty AutoScrollProperty = DependencyProperty.Register("AutoScroll", typeof(bool), typeof(UserWidgetSettings));

  ... more settings ...
}

public class UserWidgetSettingsStorage
{
  public static readonly UserWidgetSettingsStorage Current = new UserWidgetSettingsStorage();

  private Dictionary<Pair<User,Widget>, WeakReference<UserWidgetSettings>> _cache;


  public UserWidgetSettings GetSettings(User user, Widget widget)
  {
    ... code to retrieve settings from file, registry, etc ...
  }
  public void Savechanges()
  {
    ... code to iterate the cache and save back changes to UserWidgetSettings objects ...
    ... called on Application.OnExit and perhaps other times ...
  }
}

Теперь вашим ViewModels, используемым представлениями, просто нужно свойство для доступа к настройкам:

public class SomeViewModel
{
  public Widget Widget { get; set; }

  ... regular view model code ...

  public UserWidgetSettings UserSettings
  {
    get
    {
      return             UserWidgetSettingsStorage.Current.GetSettings(
          MyApp.CurrentUser, Widget);
    }
  }

}

По вашему мнению, вы можете использовать настройки следующим образом:

<SomeControl AutoScroll="{Binding UserSettings.AutoScroll}" />

А ваш флажок для управления выглядит так:

<CheckBox IsChecked="{Binding UserSettings.AutoScroll}" />

Примечание: я обнаружил, что в среднем только около 20% моих просмотров действительно нуждаются в собственной модели представления. Остальные могут использовать общие свойства, предоставляемые самой моделью. Если вы обнаружите, что создаете отдельную модель представления для каждого отдельного представления, что-то может быть неправильно. Возможно, вы захотите взглянуть и посмотреть, есть ли какие-то вещи, которые вы делаете в модели представления, которые имеют такой же или больший смысл в самой модели. Итог: хорошо спроектированные объекты моделей могут значительно сократить объем кода в приложении WPF.

...