Я создаю программную архитектуру программного обеспечения, разработанного в 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
1. Не согласен. Я предпочитаю не иметь наследования для чего-то, что на самом деле является сквозной проблемой, пытаясь использовать AOP для 'INPC' (см. PropertyChanged.Fody). – Aron
@Aron Thats отлично, если вы не хотите модель базового вида, я не буду спорить с вами. Тем не менее, вы не должны определять его как в базовом, так и в производном классах, поскольку базовый класс будет скрыт и потенциально может вызвать у вас всевозможные странные проблемы. – BradleyDotNET
Что вы подразумеваете под «TL», «DR» и «DC/DP»? Что вы подразумеваете под пунктом 2? (Возможно, я уже реализовал это в моих вышеупомянутых и не показанных методах.) Что касается пунктов 3 и 4, у меня есть мои причины, и кошмар для меня закончился, поскольку все синхронизировано с вышеуказанным кодом. Ну, примерно в пункте 1, я сказал, что одно событие для каждой ViewModel поможет мне в управлении событиями, и принятие этой задачи является целью текущего поста. Я не знаю, как представить управление событиями иначе. –