使用 IEventAggregator 的 Caliburn 微堆栈溢出异常

Caliburn Micro Stack Overflow Exception using IEventAggregator

我正在学习并尝试 MVVM 使用 Caliburn.Micro。我有一个主 ShellViewModel 和一个子用户控件 Module1ViewModel。我正在尝试使用 IEventAggregator.
实现它们之间的通信 现在,我可以从子控件 ShellViewModel 更改 ShellViewModel(父)的 属性,并且可以从父控件更改 属性 的子控件,它可以工作。

问题: 我面临的问题是,当我在两个 ViewModel 中启用 events.Subscribe(this); 时,出现异常。

我想要实现的是双向 种沟通方式。这意味着我想同时从子项中更改一些 属性 的父项,我应该能够从父项中更改一些 属性 的子项。以下是我的代码,请检查这里有什么问题。

子用户控制模块1ViewModel

    namespace IntelliCoreMVVM.ViewModels
    {
        public class Module1ViewModel:Screen , IHandle<string>
        {
            private IEventAggregator _events;
            public Module1ViewModel(IEventAggregator events)
            {
                _events = events;
                events.Subscribe(this);
            }
            private string _firstName;
            public string FirstName
            {
                get { return _firstName; }
                set
                {
                    _firstName = value;
                    NotifyOfPropertyChange(()=>FirstName);
                    _events.PublishOnUIThread(FirstName);
                }
            }

            public void Handle(string message)
            {
                FirstName = message;
            }
        }
    }  

如您所见,我正在发布和处理 属性。

ShellViewModel


    public class ShellViewModel : Conductor<object> , IHandle<string>
            {
                private Module1ViewModel _module1ViewModel;
                private IEventAggregator _events;
                public ShellViewModel(Module1ViewModel module1ViewModel,IEventAggregator events)
                {
                    _events = events;
                    events.Subscribe(this);
                    _module1ViewModel = module1ViewModel;
                }
                private string _test;
                private string _firstName;
                public string FirstName
              {
               get { return _firstName; }
               set
                 {
                  _firstName = value;
                   NotifyOfPropertyChange(()=>FirstName);
                  _events.PublishOnUIThread(new CustomerModel{FirstName =     FirstName});
                 }
                }
                public string Test
                {
                    get { return _test; }
                    set
                    {
                        _test = value; 
                        NotifyOfPropertyChange(()=>Test);
                    }
                }
                public void Handle(string message)
                {
                    Test = message;
                }
          }

快速观看
堆栈调用

问题是您的 VM 正在递归地相互更新和自我更新,例如订阅 IEventAggregator 并处理字符串消息,而不是更新 属性 并再次发布相同的消息,某种无限循环。您可以引入一个类型化的事件来处理从父到子,反之亦然,而不仅仅是字符串

public class ChildEvent
{
    public string Name { get; set; }
}

public class ParentEvent
{
    public string Name { get; set; }
}    
public class ShellViewModel : Conductor<object>, IHandle<ChildEvent>
{
    private readonly IEventAggregator _events;
    public ShellViewModel(IEventAggregator events)
    {
        _events = events;
        events.Subscribe(this);
    }
    private string _test;

    public string Test
    {
        get => _test;
        set
        {
            _test = value;
            NotifyOfPropertyChange(() => Test);
        }
    }
    public void Handle(ChildEvent message)
    {
        Test = message.Name;
    }
}

public class Module1ViewModel : Screen, IHandle<ParentEvent>
{
    private readonly IEventAggregator _events;
    public Module1ViewModel(IEventAggregator events)
    {
        _events = events;
        events.Subscribe(this);
    }
    private string _firstName;
    public string FirstName
    {
        get => _firstName;
        set
        {
            _firstName = value;
            NotifyOfPropertyChange(() => FirstName);
        }
    }

    public void Handle(ParentEvent message)
    {
        FirstName = message.Name;
    }
}

顺便说一句,在使用 IEventAggregator 的情况下,您不需要 ShellViewModel 中的 Module1ViewModel 引用。也不要在 setter 中立即触发事件,因为它可以在视图模型之间触发无限事件循环

FirstName 引发调用 Handle 的事件,它再次设置 FirstName 然后它在无限循环中像这样继续下去,直到你 运行 出栈 space 并得到 WhosebugException.

问题是 Module1ViewModel 处理 所有 string 事件,包括它自己引发的事件。

您可能想要做的是定义不同类型的事件,以便您可以区分它们并选择要处理的事件。在下面的示例中,Module1ViewModel 处理类型 ParentToChildEvent 的事件,但它引发类型 ChildToParentEvent 的事件。 ShellViewModel 应该相反。

public class Module1ViewModel : Screen, IHandle<ParentToChildEvent>
{
    private IEventAggregator _events;
    public Module1ViewModel(IEventAggregator events)
    {
        _events = events;
        events.Subscribe(this);
    }
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            _firstName = value;
            _events.PublishOnUIThread(new ChildToParentEvent(FirstName));
        }
    }

    public void Handle(string message)
    {
        FirstName = message;
    }
}