I am creating the program-side architecture of a software developped in WPF, I designed the architecture as being compliant with the MVVM pattern.
For many sakes (design, coherence, reusability, maintainability, scalability, etc) I created the class BaseViewModel
implementing the interface INotifyPropertyChanged
and some other methods:
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() { }
}
The above-defined class BaseViewModel
is used as a base class for all the other ViewModel
s of the application (or, at least, is meant to be so), for example:
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() { }
}
I use the class SampleViewModel
as the DataContext
of SampleUserControl
which bares a 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;
}
}
}
}
To sum up, the data relative to SampleUserControl
are contained at three locations : the instance of SampleViewModel
, within TextProperty
and within the property Text
of a TextBox
in the xaml part of SampleUserControl
(this property Text
is twoway-bound through Binding
with the field Name
of ViewModel
).
To synchronize the three values, I added the methods TextPropertyChangedCallback
and ViewModel_PropertyChanged
which update the fields which need to be updated.
The above code works and the three above-mentionned locations are kept up-to-date, events fire and so on, things are fine when SampleUsercontrol
is consumed with data-binding.
But SampleViewModel
fires the event BaseViewModel.PropertyChanged
, and since BaseViewModel
is meant to be extensively used, I would like each ViewModel
to have its own event PropertyChanged
, at least in order to avoid overlapping events.
So I uncomment the code of SampleViewModel
thus redefining the event PropertyChanged
but it breaks down the synchronization between the field Name
of the instance of SampleViewModel
and the property TextProperty
of SampleUserControl
.
Am I making some mistakes on the conception side? Do you have any guidance for me? What is the best economic way of defining a different event PropertyChanged
for each ViewModel inheriting from BaseViewModel
while still using the general-purpose methods defined within that base class (such methods use PropertyChanged
)? (I would like to avoid having heavy pieces of code to copy-paste.)
I know that it is more about optimization, but such optimizations can make a difference between a slow software and a fast one. I am at the stage of code-factoring, so I fancy nicely-shaped, elegant and factorized code.
End of the day happening, I may miss some obvious solutions.
Thanks in advance for any clue, Julien
TL;DR: Basically, I would double-check that you are doing your DC/DP on that user control correctly, and toss out any concept of multiple definitions of PropertyChanged
In detail:
PropertyChanged
in the base class, which is great. There is no reason to ever redefine it anywhere else . Really, you are just asking for trouble by doing this. handler
bit in the settter. Insta-reduction of copy paste. TextPropertyChanged
is a huge red flag here. Which relates to the real problem, that you are probably abusing your dependency property. DPs are used to allow parent controls to bind to a property of your user control. You typically won't use them in conjunction with a data context internal to the control because, as you have seen, keeping them in sync is a nightmare.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.