Скажем, в некотором абстрактном базовом классе ViewModel у меня есть простое свойство следующим образом:
public Size Size
{
get { return _size; }
set
{
_size = value;
OnPropertyChanged("Size");
}
}
Я тогда создаю более определенный ViewModel, наследовавшийся предыдущему, который содержит следующее свойство:
public Rect Rectangle
{
get { return new Rect(0, 0, _size.Width, _size.Height); }
}
Теперь, в некотором классе Представления я связываю с вышеупомянутым ViewModel Rectangle
свойство. Все хорошо работает, пока я не изменяю размер. Когда Size
изменения, Rectangle
не знает об этом, и изменение не распространяет к Представлению. И с тех пор Rectangle
находится в дочернем классе, я не могу просто добавить OnPropertyChanged("Rectangle")
к Size
метод set.
Теперь предположите, что у меня есть много различных свойств как Rectangle
, это все зависит от свойств базового класса, и что ни одно из этих изменений не распространяется. Мне нужен некоторый легкий и изящный способ объединить уведомления об изменении в цепочку, предпочтительно то, которое не требует большого количества кода и не принуждает меня к использованию свойств зависимости.
Очевидно, существует много ужасных решений здесь - что я ищу, что-то чистое и умное. Это кажется мне, это было бы очень общим сценарием, и это кажется мне мог бы быть MVVM-дружественный способ сделать это.
Я недавно писал в блоге об этой конкретной проблеме. Я включил атрибут [DependsUpon("Размер")]
с Прямоугольником. Мне РЕАЛЬНО нравится этот подход, потому что он хранит знания о зависимостях с помощью кода, который создает зависимость, а не наоборот.
Вы можете просто переопределить OnPropertyChanged в производной ViewModel так:
protected override void OnPropertyChanged(string propertyName) {
base.OnPropertyChanged(propertyName);
if (propertyName == "Size") {
base.OnPropertyChanged("Rectangle");
}
}
Другая возможность .... Некоторое время назад я собрал довольно неплохой базовый класс ViewModel, который поддерживает атрибуты на свойствах типа:
[DependsOn("Size")]
public Rect Rectangle {
get { new Rect(0,0,Size.Width, Size.Height); }
}
Затем базовый класс ViewModel собирает их DependsOnAttribute's во время выполнения, и в своем методе OnPropertyChanged он в основном просто смотрит, какие еще свойства нужно сделать недействительными при смене свойства.
. Чистым способом MVVM было бы использование механизма подписки/уведомления Messenger
(как в Josh Smith's MvvmFoundation)
Создать где-нибудь однотонный объект Messenger - основной класс App всегда является хорошим местом для этого
public partial class App : Application
{
private static Messenger _messenger;
public static Messenger Messenger
{
get
{
if (_messenger == null)
{
_messenger = new Messenger();
}
return _messenger;
}
}
}
В Setter'е Размеры из базового класса, уведомляйте об изменениях:
public Size Size
{
get { return _size; }
set
{
_size = value;
OnPropertyChanged("Size");
App.Messenger.NotifyColleagues("SIZE_CHANGED");
}
}
Теперь вы можете позволить унаследованной ViewModel'ом прослушивать эти изменения, и вызывать события PropertyChanged соответствующим образом. ..
public MyViewModel : MyViewModelBase
{
public MyViewModel()
{
App.Messenger.Register("SIZE_CHANGED", () => OnPropertyChanged("Rectangle"));
}
}
Конечно - вы можете добавить столько подписок на это сообщение, сколько вам нужно - по одной на каждое свойство, которое нуждается в уведомлении об изменениях....
Надеюсь, это поможет :)
может быть, потому что я парень из VB, но в вашем прямоугольном коде это выглядит так, как будто вы получаете доступ к приватному объявлению _размеров вместо свойства Public Size, которое не будет увольнять событие OnPropertyChanged, чтобы предупредить просмотр.
Также я могу быть вне базы, но не должен ли Прямоугольник быть реальным объектом, в то время как Размер является свойством этого объекта? Может быть, это то, что вы делаете... некоторые методологии C# до сих пор действительно чужие для меня.
Я использую PropertyObserver Джоша Смита, который вы можете получить из его библиотеки MVVM Foundation по адресу http://mvvmfoundation.codeplex.com/ .
Использование:
_viewmodel_observer = new PropertyObserver<OtherViewModel>(_OtherViewModel)
.RegisterHandler(m => m.Size, m => RaisePropertyChanged(Rectangle);
Атрибутный подход Брайана тоже хорош. В PropertyObserver мне нравится то, что я могу выполнять произвольный код; позволяя мне проверить условия, которые могут заставить меня избежать повышения или выполнить другие действия все вместе.