Уведомление об изменении в иерархиях MVVM

Скажем, в некотором абстрактном базовом классе 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-дружественный способ сделать это.

15
задан Charlie 5 January 2010 в 23:51
поделиться

5 ответов

Я недавно писал в блоге об этой конкретной проблеме. Я включил атрибут [DependsUpon("Размер")] с Прямоугольником. Мне РЕАЛЬНО нравится этот подход, потому что он хранит знания о зависимостях с помощью кода, который создает зависимость, а не наоборот.

Взгляните: http://houseofbilz.com/archive/2009/11/14/adventures-in-mvvm----dependant-properties-with-inotifypropertychanged.aspx

9
ответ дан 1 December 2019 в 04:09
поделиться

Вы можете просто переопределить 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 он в основном просто смотрит, какие еще свойства нужно сделать недействительными при смене свойства.

.
3
ответ дан 1 December 2019 в 04:09
поделиться

Чистым способом 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"));
    }
}

Конечно - вы можете добавить столько подписок на это сообщение, сколько вам нужно - по одной на каждое свойство, которое нуждается в уведомлении об изменениях....

Надеюсь, это поможет :)

1
ответ дан 1 December 2019 в 04:09
поделиться

может быть, потому что я парень из VB, но в вашем прямоугольном коде это выглядит так, как будто вы получаете доступ к приватному объявлению _размеров вместо свойства Public Size, которое не будет увольнять событие OnPropertyChanged, чтобы предупредить просмотр.

Также я могу быть вне базы, но не должен ли Прямоугольник быть реальным объектом, в то время как Размер является свойством этого объекта? Может быть, это то, что вы делаете... некоторые методологии C# до сих пор действительно чужие для меня.

0
ответ дан 1 December 2019 в 04:09
поделиться

Я использую PropertyObserver Джоша Смита, который вы можете получить из его библиотеки MVVM Foundation по адресу http://mvvmfoundation.codeplex.com/ .

Использование:

_viewmodel_observer = new PropertyObserver<OtherViewModel>(_OtherViewModel)
   .RegisterHandler(m => m.Size, m => RaisePropertyChanged(Rectangle);

Атрибутный подход Брайана тоже хорош. В PropertyObserver мне нравится то, что я могу выполнять произвольный код; позволяя мне проверить условия, которые могут заставить меня избежать повышения или выполнить другие действия все вместе.

4
ответ дан 1 December 2019 в 04:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: