Подтвердить что ты не робот

WPF: как сигнализировать событие из ViewModel для просмотра без кода в codebehind?

У меня довольно простая (я надеюсь:)) проблема:

В MVVM View обычно прослушивает изменения свойств ViewModel. Тем не менее, мне иногда хотелось слушать событие, так что, например, View мог бы начать анимацию или закрыть окно, когда сигналы VM.

Выполнение этого с помощью свойства bool с NotifyPropertyChanged (и запуск анимации только при изменении от false до true) возможно, но это похоже на хак, я бы предпочел разоблачить событие, поскольку оно семантически корректно.

Кроме того, я хотел бы сделать это без кода в codebehind, так как do viewModel.myEvent += handler означало бы, что я бы вручную отменил регистрацию события, чтобы позволить View быть GC'd - WPF Views уже доступны для слабого прослушивания свойств, и я бы предпочел программировать только декларативно в представлении.

Стандартная подписка на сильное событие также плоха, потому что мне нужно переключить несколько ViewModels для одного представления (потому что при создании View каждый раз требуется слишком много времени процессора).

Спасибо за идеи (если есть стандартное решение, достаточно ссылки на msdn)!

4b9b3361

Ответ 2

Некоторые комментарии:

  • Вы можете использовать слабый шаблон события, чтобы гарантировать, что представление может быть GC'd, даже если оно все еще привязано к модели представления событие
  • Если вы уже переключаете несколько виртуальных машин на один вид, не было бы идеальным местом для прикрепления/отсоединения обработчика?
  • В зависимости от вашего точного сценария вы можете просто заставить VM выставить свойство состояния, которое вид использует как триггер для анимаций, переходов и других визуальных изменений. Визуальный менеджер состояний отлично подходит для такого рода вещей.

Ответ 3

Этот поток довольно старый, но я предоставил свои $0,02, потому что это то, с чем я боролся, а также недавно...

Подобно тому, что говорят другие, но вот пример с некоторыми фрагментами кода... В этом примере показано, как использовать pub/sub, чтобы иметь возможность подписываться на событие, выпущенное виртуальной машиной, - в этом случае я делаю Вид сетки. Восстановите, чтобы gv синхронизировался с VM...

Просмотр (Sub):

 using Microsoft.Practices.Composite.Events;
 using Microsoft.Practices.Composite.Presentation.Events;

 private SubscriptionToken getRequiresRebindToken = null;

    private void SubscribeToRequiresRebindEvents()
    {
        this.getRequiresRebindToken =
            EventBus.Current.GetEvent<RequiresRebindEvent>()
            .Subscribe(this.OnRequiresRebindEventReceived, 
                ThreadOption.PublisherThread, false,
                MemoryLeakHelper.DummyPredicate);
    }

    public void OnRequiresRebindEventReceived(RequiresRebindEventPayload payload)
    {
        if (payload != null)
        {
            if (payload.RequiresRebind)
            {
                using (this.gridView.DeferRefresh())
                {
                    this.gridView.Rebind();
                }
            }
        }
    }

    private void UnsubscribeFromRequiresRebindEvents()
    {
        if (this.getRequiresRebindToken != null)
        {
            EventBus.Current.GetEvent<RequiresRebindEvent>()
                .Unsubscribe(this.getRequiresRebindToken);
            this.getRequiresRebindToken = null;
        }
    }

Вызовите unsub из метода закрытия, чтобы предотвратить утечку памяти.

ViewModel (Pub):

 private void PublishRequiresRebindEvent()
 {
      var payload = new RequiresRebindEventPayload();
      payload.SetRequiresRebind();
      EventBus.Current.GetEvent<RequiresRebindEvent>().Publish(payload);
 }

Класс полезной нагрузки

using System;
using Microsoft.Practices.Composite.Presentation.Events;

public class RequiresRebindEvent 
    : CompositePresentationEvent<RequiresRebindEventPayload>
{

}

public class RequiresRebindEventPayload
{
    public RequiresRebindEventPayload()
    {
        this.RequiresRebind = false;
    }

    public bool RequiresRebind { get; private set; }

    public void SetRequiresRebind()
    {
        this.RequiresRebind = true;
    }
}

Обратите внимание, что вы также можете установить конструктор для передачи в Guid или некоторые из них, которые могут быть установлены на Pub и проверены на sub, чтобы убедиться, что pub/sub синхронизирован.

Ответ 4

imho yY и разделенные

  • состояние - возможность перемещения данных назад/вперед между представлением ↔ vm
  • действия - возможность вызова функций/команд модели просмотра
  • уведомления - чтобы иметь возможность сигнализировать о том, что что-то произошло, и вы хотите, чтобы он выполнял видимые действия, такие как создание элемента свечения, стилей переключения, изменение макета, фокусировка другого элемента и т.д.

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

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

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

Ответ 5

Как и Adrianm, когда вы запускаете свою анимацию из свойства bool, вы фактически отвечаете на событие. В частности, событие PropertyChanged, которое подсистема WPF. Который предназначен для правильной установки/отсоединения, чтобы вы не просачивали память (вы можете забыть это сделать при проводке события самостоятельно и вызвать утечку памяти путем ссылки на объект, который в противном случае должен быть GCed),

Это позволяет вам отображать ViewModel как DataContext для элемента управления и правильно реагировать на изменение свойств в datacontext посредством привязки данных.

MVVM - это шаблон, который особенно хорошо работает с WPF из-за всех этих вещей, которые дает WPF, и выключение изменения свойств на самом деле является изящным способом использования всей подсистемы WPF для достижения ваших целей:)

Ответ 6

Более общий вопрос: "Почему я пытаюсь разобраться с этим событием в моей модели ViewModel?"

Если ответ имеет какое-то отношение к объектам, похожим только на просмотр, например анимация, я бы сказал, что ViewModel не должен знать об этом: код позади (когда это необходимо), Data/Event/PropertyTriggers и новые конструкции VisualStateManager будут служить вы намного лучше и поддерживаете чистое разделение между View и ViewModel.

Если что-то должно "произойти" в результате события, то то, что вы действительно хотите использовать, - это шаблон команды - либо с помощью CommandManger, обработки события в коде позади и вызова команды в модели представления, или используя прикрепленные поведения в библиотеках System.Interactivity.

В любом случае, вы хотите, чтобы ваш ViewModel был "чистым", как вы можете, - если вы видите что-то видимое в нем, вы, вероятно, ошибаетесь.:)