-
Notifications
You must be signed in to change notification settings - Fork 6
ViewModel
The ViewModel
abstract class provides a base implementation for a viewmodel in the MVVM architecture. It implements the INotifyPropertyChanging
, INotifyPropertyChanged
and INotifyDataErrorInfo
interfaces by inheriting from ValidatingBindable
and has some additional features.
ViewModel
implements an IsDirty
property which is initially false.
If the PropertyChanged
event handler is raised and the IsDirtyIgnoredAttribute
is not defined on the property (or on notified properties via PropertySourceAttribute
), IsDirty
will be set to true.
private bool _myProperty;
[IsDirtyIgnored]
public bool MyProperty
{
get => _myProperty;
set => SetProperty(ref _myProperty, value);
}
In this example, when MyProperty
changes, IsDirty
will not be automatically set to true.
Also, if the property implements INotifyCollectionChanged
and no IsDirtyIgnoredAttribute
exists, the ViewModel
will attach itself to the CollectionChanged
event handler and set IsDirty
to true every time it's raised. When the collection property has a setter, please use the SetProperty<T>
method to properly detach and attach from the event handler.
ViewModel
implements a Parent
property which internally uses a WeakReference<T>
to prevent reference cycles.
ViewModel
implements an IsReadOnly
property. If set to true, the SetProperty<T>
methods will no longer set any properties or raise events on the PropertyChanging
and PropertyChanged
event handlers.
An exception is the IsReadOnly
property itself or any property with the IsReadOnlyAttribute
.
ViewModel
implements an IsUpdating
property. This property can be used to indicate if the instance is currently being updated.
The IsValid
property is a convenient way to, for example, bind to the IsEnabled
state of a button without the use of a converter to invert the value of HasErrors
.
The PropertySourceAttribute
on a property indicates that the property depends on other properties and that they should be reevaluated, if any of the named properties change.
Thus, the NotifyPropertyChanging
and NotifyPropertyChanged
methods will automatically raise additional events when an event is raised for one of named properties.
When a property is overriden in a subclass, attributes are not inherited by default. As the overriden property most probably has different dependecies, you should redeclare the PropertySourceAttribute
with the new dependencies.
public class Base
{
[IsDirtyIgnored]
public bool TestProperty { get; }
[PropertySource(nameof(TestProperty))]
public virtual bool AnotherTestProperty => TestProperty;
}
public class Derived : Base
{
public override bool AnotherTestProperty => true;
}
In that example, when using Derived
, only the IsDirtyIgnoredAttribute
from TestProperty
is processed since this property is not overridden.
No event on PropertyChanged
will be raised for AnotherTestProperty
when TestProperty
changes.
If you access the base implementation in the override, you should define a PropertySourceAttribute
with the InheritAttributes
option set to true. In that case you can also define additional sources.
public class Base
{
public bool TestProperty { get; }
[PropertySource(nameof(TestProperty))]
public virtual bool AnotherTestProperty => TestProperty;
}
class Derived : Base
{
public bool NewTestProperty { get; }
[PropertySource(nameof(NewTestProperty), InheritAttributes = true)]
public override bool AnotherTestProperty => base.AnotherTestProperty && NewTestProperty;
}