在MVVMCross上从ViewModel执行UI代码
我刚开始使用MvvmCross,但我没有找到任何关于如何从ViewModel执行UI代码的信息。
在Caliburn上有coroutine,所以我可以访问视图并保持ui代码与viewmodel代码分开。 在我的第一个案例中,我需要从ViewModel中的命令打开一个拨号,这是正确的方法吗?
现在我正在开发一个WinRT应用程序。
谢谢
MvvmCross中没有任何硬/快的规则。
通常,当我需要这样做时,我使用Messenger插件。
此答案假设您使用的是最新的Alpha v3
代码。 对于较旧的vNext代码,您必须进行一些翻译 – 请参阅下面的注释。
要使用此方法:
我从Core和UI项目中引用了Cirrious.MvvmCross.Plugins.Messenger.dll
。
然后我在Setup.cs中的某个地方添加一行(例如在InitializeLastChance
):
Cirrious.MvvmCross.Plugins.Messenger.PluginLoader.Instance.EnsureLoaded();
然后在Core项目中我添加一条消息:
public class InputIsNeededMessage : MvxMessage { public InputIsNeededMessage(object sender) : base(sender) {} }
在ViewModel中,我可以通过构造函数注入或通过以下方式获取Messenger:
var messenger = Mvx.Resolve();
我可以通过以下方式发送消息:
messenger.Publish(new InputIsNeededMessage(this));
在视图中,我可以再次访问信使并使用以下命令订阅消息:
var messenger = Mvx.Resolve(); _token = messenger.SubscribeOnMainThread(OnInputIsNeeded);
其中_token
必须是成员变量 – 如果不是,那么订阅将不会持久 – 默认情况下订阅本身很弱 (所以你永远不必取消订阅)
以及OnInputIsNeeded
的类似于:
private void OnInputIsNeeded(InputIsNeededMessage message) { if (message.Sender != ViewModel) return; // do stuff here - you are already on the UI thread }
以上序列是我通常为“正确代码”所做的
首先使用Messenger / EventAggregator会感到不舒服 – 它肯定花了我一段时间才习惯它 – 但是在我习惯了它之后,我现在到处使用它 – pub / sub Message decoupling非常灵活测试和未来的代码维护(IMO)
作为上述方法的替代方案,我有时会采取捷径:
- 有时我会从ViewModel中激活正常的C#事件,并让View响应这些事件
- 有时我有特殊的标记属性并从中激活UI代码
很抱歉使用v3
语法 – 但转换即将到来,这就是我现在编写的内容……
要切换回vNext
我认为您可能需要:
- 使用
IMessenger
而不是IMvxMessenger
- 使用
BaseMessage
而不是MvxMessage
- 使用
Subscribe
而不是SubscribeOnMainThread
– 但是你需要自己将消息编组到UI线程上。
有一种更简单的方法。 这是我用于在主线程上执行任何操作的方法:
protected void RunOnUIThread(Action action) { var dispatcher = Mvx.Resolve(); dispatcher.RequestMainThreadAction(action); }
希望能帮助到你。 干杯。