Caliburn.Micro и агрегатор событий - нежелательный метод обработки вызовов - PullRequest
2 голосов
/ 25 декабря 2010

У меня одна проблема с публикацией / обработкой сообщений между двумя экранами.

Мой сценарий:

  1. Экран мессенджера, является ли он главным экраном, публикуется на экранах чата, они являются ведомыми экранами. Дескриптор модели представления Messenger с сообщениями с сервера.

  2. Экран чата может публиковать сообщения на экране мессенджера. И модель представления мессенджера отправляет это сообщение на сервер.

Класс Messenger выглядит следующим образом:

 [Export("MessengerScreen", typeof(IMessengerViewModel))]
    public class MessengerViewModel : Screen, IMessengerViewModel, IInitializable<Account>, IHandle<Rp>
    {
        // ...

        [ImportingConstructor]
        public MessengerViewModel(IPokecService service, IEventAggregator eventAgg)
        {
            _eventAgg = eventAgg;
            _eventAgg.Subscribe(this);
        }


        //publish on slave screen 
        public void Publish(Rp rp)
        {
            _eventAgg.Publish(rp);
        }

        //handle msg from slave screen
        public void Handle(Rp msg)
        {
            //send to server
        }
    }

Класс ведомого экрана выглядит следующим образом:

   [Export("ChatScreen", typeof(IChatViewModel))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class ChatViewModel : Screen, IInitializable<DetailData>, IHandle<Rp>
    {
        [ImportingConstructor]
        public ChatViewModel(IEventAggregator eventAgg)
        {
            _eventAgg = eventAgg;
            _eventAgg.Subscribe(this);
        }

        //publish only on messenger screen
        public void Publish(Rp rp)
        {
            _eventAgg.Publish(rp);
        }

        //show message from published from messenger
        public void Handle(Rp rp)
        {
            AddBlockToConversation(rp);
        }

        //if enter is pressed publish on messanger screen
        public void SendRp(KeyEventArgs e)
        {
            if (e.Key == Key.Enter && !string.IsNullOrEmpty(RpText))
            {
                _yourRp.Time = String.Format("{0:yyyy-MM-dd HH:mm:ss}", DateTime.Now);

                _yourRp.RpText = RpText;

                AddBlockToConversation(_yourRp);


                //publish on messanger screen
                Publish(_yourRp);
            }
        }
    }

Мои проблемы:

Первая проблема:

  • я вызываю метод SendRp из класса ChatViewModel.
  • Вызывает метод void Publish () в ChatViewModel,
  • тогда вызывается метод void Handle () из класса MessengerViewModel
  • , а затем вызвать также метод void Handle () из класса ChatViewModel.

Я не хочу вызывать метод Handle () в классе ChatViewModel. Почему, если я отправляю сообщение из ChatViewModel в MessengerViewModel, это также называется методом Handle в классе ChatViewModel?

Моя вторая проблема:

Я хочу опубликовать сообщение из MessengerViewModel только на определенном ведомом экране.

MessgerVieModel имеет в очереди сообщения: {msg1, msg2, msg3, ..., msgN}

Я хотел бы опубликовать:

  • msg1 на ведомом экране № 1.
  • msg2 на ведомом экране # 2
  • ...
  • msg3 на ведомом экране # 3

1 Ответ

2 голосов
/ 26 декабря 2010

МОЕ РЕШЕНИЕ: Я решил свою проблему с модификацией класса EventAggregator.

Примерно так:

Каждая модель моего представления реализует этот интерфейс:

public interface  IViewModelIdentity
{
    string ScreenIdentity { get; set; }
}

И в методе Publish в классе четного агрегатора у меня есть это:

 public void Publish(Rp rp)
        {

            WeakReference[] toNotify;
            lock (_subscribers)
                toNotify = _subscribers.ToArray();

            Execute.OnUIThread(() =>
            {
                Log.Info("Publishing {0}.", rp);
                var dead = new List<WeakReference>();

                foreach (var reference in toNotify)
                {
                    var target = reference.Target as IHandle<Rp>;

                    //GET ID OF SCREEN
                    var screenId = reference.Target as IViewModelIdentity;

                    //!
                    if (target != null && screenId != null)
                    {
                        if (screenId.ScreenIdentity=="screen on which we want to send a message")
                        {
                            //PUBLISH ON SCREEN
                            target.Handle(rp);
                        }
                    }
                    else if (!reference.IsAlive)
                        dead.Add(reference);
                }
                if (dead.Count > 0)
                {
                    lock (_subscribers)
                        dead.Apply(x => _subscribers.Remove(x));
                }
            });
        }
...