2015-08-14 2 views
2

Я создаю программную архитектуру программного обеспечения, разработанного в WPF, я разработал архитектуру как совместимую с шаблоном MVVM.События, методы, использующие эти события и наследование

Для многой пользы (дизайн, согласованность, возможности многократного использования, ремонтопригодность, масштабируемость и т.д.) Я создал класс BaseViewModel, реализующий интерфейс INotifyPropertyChanged и некоторые другие методы:

public class BaseViewModel: INotifyPropertyChanged 
{ 
    private PropertyChangedEventHandler property_changed; 
    public event PropertyChangedEventHandler PropertyChanged 
    { 
     add { property_changed += value; } 
     remove { property_changed -= value; } 
    } 

    //Here several methods using PropertyChanged and easing the usage of ViewModels 

    public BaseViewModel() { } 
} 

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

public class SampleViewModel : BaseViewModel 
{ 
    //private PropertyChangedEventHandler property_changed; 
    //public event PropertyChangedEventHandler PropertyChanged 
    //{ 
    // add { property_changed += value; } 
    // remove { property_changed -= value; } 
    //} 

    public String Name 
    { 
     get { return name; } 
     set 
     { 
      if(value != name) 
      { 
       name = value; 
       var handler = PropertyChanged; 
       if(handler != null) 
       { 
        handler(this, new PropertyChangedEventArgs("Name")); 
       } 
      } 
     } 
    } 
    private String name = ""; 

    public SampleViewModel() 
     : base() { } 
} 

Я использую класс SampleViewModel как DataContext из SampleUserControl, который обнажает DependencyProperty:

public partial class SampleUserControl : UserControl 
{ 
    #region ViewModel 
    public SampleViewModel ViewModel 
    { 
     get { return view_model; } 
    } 
    private SampleViewModel view_model = new SampleViewModel(); 
    #endregion 

    #region DependencyProperty 
    public String Text 
    { 
     get { return (String)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 
    public static readonly DependencyProperty TextProperty = 
     DependencyProperty.Register("Text", typeof(String), typeof(SampleUserControl), 
       new FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.AffectsRender, 
         new PropertyChangedCallback(TextPropertyChangedCallback))); 
    private static void TextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     SampleUserControl sender = d as SampleUserControl; 
     if (sender != null) 
     { 
      sender.ViewModel.Name = (String)e.NewValue; 
     } 
    } 
    #endregion 

    public SampleUserControl() 
    { 
     InitializeComponent(); 
     LayoutRoot.DataContext = ViewModel; 
     ViewModel.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged); 
    } 

    void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
     SampleViewModel viewmodel = sender as SampleViewModel; 
     if (viewmodel != null) 
     { 
      switch (e.PropertyName) 
      { 
       case "Name": 
        SetValue(TextProperty, viewmodel.Name); 
        break; 
       default: 
        break; 
      } 
     } 
    } 
} 

Чтобы подвести итог, данные по отношению к SampleUserControl содержатся в трех местах: экземпляр SampleViewModel, внутри TextProperty и в собственности Text о наличии TextBox в xaml часть SampleUserControl (это свойство Text является twoway-bound через Binding с полем Name из ViewModel).

Чтобы синхронизировать три значения, я добавил методы TextPropertyChangedCallback и ViewModel_PropertyChanged, которые обновляют поля, которые необходимо обновить.

Приведенный выше код работает, и три вышеупомянутых местоположения постоянно обновляются, огонь событий и т. Д., Все прекрасно, когда SampleUsercontrol потребляется с привязкой данных.

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

Так я раскомментировать код SampleViewModel таким образом, переопределение PropertyChanged, но это ломает синхронизацию между полем Name экземпляра SampleViewModel и свойство TextProperty из SampleUserControl.

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

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

Конец дня, я могу пропустить некоторые очевидные решения.

Спасибо заранее за любую подсказку, Julien

ответ

0

TL; DR: В принципе, я бы дважды проверьте, что вы делаете ваш DC/DP на этом пользовательский элемент управления правильно, и бросьте любую концепцию нескольких определений из PropertyChanged

подробно:

  1. Вы определили PropertyChanged в базовом классе, который является большим. Нет причин, чтобы когда-либо пересмотреть его в любом месте еще. На самом деле, вы просто просите о неприятностях, делая это.
  2. Для этого необходимо действительно просто сделайте способ делать вызов события, а не делать весь бит handler в настройке. Insta-сокращение копий.
  3. Тот факт, что вам нужно использовать TextPropertyChanged, является огромным красным флагом. Что касается реальной проблемы, вы, вероятно, злоупотребляете своим имуществом зависимостей. DP используются для разрешения родительских элементов для привязки к свойству вашего пользовательского элемента управления. Обычно вы не будете использовать их в сочетании с внутренним контекстом данных для элемента управления, потому что, как вы видели, синхронизация - это кошмар.
  4. В общем, пользовательские элементы управления должны иметь свой собственный контекст данных, если они настроены так, чтобы выделяться отдельно от любого другого элемента управления (т. Е. Под-представления). Если они всего лишь причудливый контроль, то предоставление ими модели взгляда редко дает вам что-либо.
+0

1. Не согласен. Я предпочитаю не иметь наследования для чего-то, что на самом деле является сквозной проблемой, пытаясь использовать AOP для 'INPC' (см. PropertyChanged.Fody). – Aron

+1

@Aron Thats отлично, если вы не хотите модель базового вида, я не буду спорить с вами. Тем не менее, вы не должны определять его как в базовом, так и в производном классах, поскольку базовый класс будет скрыт и потенциально может вызвать у вас всевозможные странные проблемы. – BradleyDotNET

+0

Что вы подразумеваете под «TL», «DR» и «DC/DP»? Что вы подразумеваете под пунктом 2? (Возможно, я уже реализовал это в моих вышеупомянутых и не показанных методах.) Что касается пунктов 3 и 4, у меня есть мои причины, и кошмар для меня закончился, поскольку все синхронизировано с вышеуказанным кодом. Ну, примерно в пункте 1, я сказал, что одно событие для каждой ViewModel поможет мне в управлении событиями, и принятие этой задачи является целью текущего поста. Я не знаю, как представить управление событиями иначе. –

Смежные вопросы