Я использую " Simple MVVM Toolkit " (MVVM
noob здесь), чтобы разработать приложение WPF для С#.
У меня есть модель класса A
:
public class A : ModelBase<A>
{
//properties, constructors, methods..
}
.. и еще один класс модели B
который наследует от A
но предоставляет свойство, которое A
не имеет:
public class B : A
{
private string additionalProperty;
public string AdditionalProperty
{
get { return additionalProperty; }
set
{
additionalProperty = value;
//NotifyPropertyChanged(m => m.AdditionalProperty); <-- problem here
}
}
}
Проблема связана с прокомментированной строкой выше: lambda в NotifyPropertyChanged
не будет работать, поскольку m.AdditionalProperty
не существует, так как m
имеет тип A
, а не B
Что происходит в этом случае? Следует отметить, что NotifyPropertyChanged
поставляется с набором инструментальных средств и не является специальной реализацией.
EDIT: Вот описание IntelliSense для NotifyPropertyChanged
в B
:
void ModelBaseCore<A>.NotifyPropertyChanged<TResult>(System.Linq.Expressions.Expression<Func<A,TResult>> property)
Позволяет указать свойство lambda для уведомления изменить
Проблема в том, как они реализовали ModelBase
. Очевидно, они не чувствовали, что кто-то будет подклассифицировать модель подклассов из ModelBase
, и я не уверен, почему они подумают об этом.
В любом случае проблема заключается в том, что вы ModelBase
какой тип использовать для разрешения, когда вы указываете общий ModelBase<A>
: ModelBase<A>
. Чтобы обойти это, вам нужно сделать довольно запутанную родовую игру, которая выглядит довольно тупой:
public class A<T> : ModelBase<T> where T : A<T>
{
//properties, constructors, methods..
}
public class B : A<B>
{
private string additionalProperty;
public string AdditionalProperty
{
get { return additionalProperty; }
set
{
additionalProperty = value;
NotifyPropertyChanged(m => m.AdditionalProperty);
}
}
}
Обратите внимание: теперь A
наследует от ModelBase<T>
not ModelBase<A>
, и вы ограничиваете T
как A<T>
. Тогда у вас есть B
наследовать от A
и указать его общий тип B
(который реализует A<T>
).
Это довольно запутанно, и я не уверен, почему они это сделали - возможно, потому что есть кросс-платформенные вещи, которые требуют от них этого. Если вам это не понадобится для кросс-платформенной работы, или, возможно, они не сделали этого по этой причине, я бы вместо этого рекомендовал вам использовать что-то вроде MVVM Light для ваших потребностей MVVM. Он имеет различную реализацию для NotifyPropertyChanged
, которая не зависит от указания его собственного типа и уменьшает необходимость в этом чрезмерном использовании дженериков.
EventManager
(новинка в .Net 4.5) для слабой связи между виртуальными EventManager
. В PRISM также есть классы, такие как ViewModelBase
и ряд других вещей, которые также помогают с MVVM. Я пишу профессиональное приложение WPF для термоусадочной пленки и использую в нем MVVMLight и PRISM, и они вполне удовлетворяют наши потребности. (Между ними много общего - мы могли бы обойтись только одним из них, если бы захотели).
Вы не ограничены свойствами параметра, переданного в лямбда. Вы также можете использовать свойства для любого объекта, который указан в родительском наборе фигурных скобок (в вашем случае сеттер). Включая "это".
Вместо:
NotifyPropertyChanged(m => m.AdditionalProperty);
Пытаться:
NotifyPropertyChanged(m => this.AdditionalProperty);
Если вы выкапываете источник, строковое значение передаваемого свойства выводится из самого параметра Expression. Помимо использования объекта для получения его свойства он вообще не используется. Это может исходить от "этого", какого-то другого объекта целиком и т.д.
NotifyPropertyChanged((B m) => m.AdditionalProperty);