【问题标题】:MVVM Light casting messagesMVVM 灯光投射消息
【发布时间】:2012-04-11 22:58:50
【问题描述】:

我有以下行为:

    public class NavigateAndBroadcastAction : NavigateToPageAction
        {
            protected override void Invoke(object parameter)
            {            
                base.Invoke(parameter);
                Messenger.Default.Send<NavigatingMessage<ViewModelBase>>(new NavigatingMessage<ViewModelBase>(this, PassedObject), NavigationToken);
            }

            public ViewModelBase PassedObject
            {
                get { return (ViewModelBase)GetValue(PassedObjectProperty); }
                set { SetValue(PassedObjectProperty, value); }
            }

            // Using a DependencyProperty as the backing store for PassedObject.  This enables animation, styling, binding, etc...
            public static readonly DependencyProperty PassedObjectProperty = DependencyProperty.Register("PassedObject", typeof(ViewModelBase), typeof(NavigateAndBroadcastAction), new PropertyMetadata(null)); 
...
    }

它基本上使用 NavigateToPageAction(在 Blend 中也可用),但允许我广播 ViewModel 对象(我使用它从列表页面导航到详细信息页面并传递所选对象)

Xaml 看起来像这样:(PassedObject 绑定到从 ViewModelBase 继承的 DetailViewModel 实例)

<i:Interaction.Triggers>
     <i:EventTrigger EventName="MouseLeftButtonDown">
         <b:NavigateAndBroadcastAction TargetPage="/View/SubjectDetailPage.xaml" NavigationToken="SubjectDetailNavigationToken" PassedObject="{Binding}" />
     </i:EventTrigger>
</i:Interaction.Triggers>

现在,我想注册消息:

Messenger.Default.Register<NavigatingMessage<DetailViewModel>>(this, NavigationToken, true, Action);

但这不起作用。有效的是注册NavigatingMessage&lt;ViewModelBase&gt;,然后将收到的消息转换为NavigatingMessage&lt;DetailViewModel&gt;。有办法解决吗?

是否可以让信使检测到正在发送的对象的实际类型并正确地传递给注册了该类型的对象?

【问题讨论】:

  • 为什么不起作用?你得到一个编译错误?例外?
  • 不,简单的消息没有送达
  • 不能发送正确类型的消息吗?
  • 好吧,我该怎么做呢?我希望行为是通用的,以便在 Xaml 中我可以绑定到从 ViewModelBase 继承的任何对象..

标签: c# silverlight mvvm mvvm-light


【解决方案1】:

一种可能的方法是使用反射来发送消息,方法是在运行时使用正确的泛型类型创建消息。
另一种是使用dynamic 和类型推断:

protected override void Invoke(object parameter)
{            
    base.Invoke(parameter);
    dynamic viewModel = PassedObject;
    Messenger.Default.Send(GetMessage(this, viewModel), NavigationToken);
}

private NavigatingMessage<T> GetMessage<T>(NavigateToPageAction action, T item)
{
    return new NavigatingMessage<T>(action, item);
}

使用反射的版本有点乱:

protected override void Invoke(object parameter)
{            
    base.Invoke(parameter);
    Send(PassedObject, NavigationToken);
}

void Send(ViewModelBase objectToSend, string navigationToken)
{
    var genericMessageType = typeof(NavigatingMessage<>)
    var viewModelType = objectToSend.GetType();
    var messageType = genericMessageType.MakeGenericType(viewModelType);
    var message = Activator.CreateInstance(messageType, this, objectToSend);

    var method = typeof(Messenger).GetMethods()
                                  .Single(x => x.Name == "Send" &&
                                               x.GetParameters().Count() == 2 &&
                                               x.GetParameters()
                                                .First()
                                                .ParameterType
                                                .GetGenericTypeDefinition()
                                                 == genericMessageType);
    method.MakeGenericMethod(viewModelType)
          .Invoke(Messenger.Default, new [] { message, navigationToken });
}

此代码假定NavigationTokenstring。如果没有,只需更改Send 方法的第二个参数的类型即可。如果Messenger 只包含Send 方法的一个重载,您可以简化Single 中的条件。另一方面,如果该方法有很多重载,则可能需要对其进行改进。

【讨论】:

  • 你能举一个反射方法的例子吗?我的目标是 WP7,事实证明,它不支持动态关键字
  • a-may-zing :) 我不得不对其进行一些修改(在 Count() == 2 之后删除了其他条件,因为它引发了异常,而不是“method.MakeGenericMethod(viewModelType)”我使用“method.MakeGenericMethod(messageType)”,它就像一个魅力:) 我不知道反射有这样的可能性:)
  • @TomášBezouška:我只使用与代码中真实名称相同的存根方法对其进行了测试。很有可能我为这些方法使用了一些错误的类型,所以你的更改应该没问题。 :-)
【解决方案2】:

如果您以Messenger.Default.Send&lt;NavigatingMessage&lt;DetailViewModel&gt;&gt;(new NavigatingMessage&lt;DetailViewModel&gt;(this, PassedObject) 发送消息,您将能够根据需要接收消息,而无需进行强制转换。

【讨论】:

  • 是的,但这会破坏行为的目的——我希望能够发送任何继承自 ViewModelBase 的对象
  • 嗯,那么恐怕你将不得不忍受铸造:(
  • @LOSTCODER:这不正确。请看我的回答,你可能会学到新东西:-)
  • @DanielHilgarth:是的,我看到了并投了赞成票! :) 真的很干净,兄弟。我知道反射会削减它,但使用动态太时尚了!非常感谢...
【解决方案3】:

这是当前版本的 MVVM Light 的限制。我正在考虑在未来改进它,但这很棘手......

【讨论】:

  • 请看我的回答。这对实现此功能有任何帮助吗? DLR 非常强大。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-15
相关资源
最近更新 更多