Silverlight MVVM灯、Windows Phone、View&;页面之间的ViewModel导航

Silverlight MVVM灯、Windows Phone、View&;页面之间的ViewModel导航,silverlight,windows-phone-7,mvvm,Silverlight,Windows Phone 7,Mvvm,我有一个页面,您基本上可以选择一组选项(配置),然后转到下一个页面,在那里您可以做一些事情 使用MVVM Light工具包,我有一个绑定到第一页视图的viewmodel。当用户点击一个按钮时,它会重定向到另一个视图,即第二页 i、 e: page2comand=newdelegatecommand((obj)=> Send(新Uri(“/dostufview.xaml”,UriKind.Relative), Common.CommonResources.GoToDoStuffRequest});

我有一个页面,您基本上可以选择一组选项(配置),然后转到下一个页面,在那里您可以做一些事情
使用MVVM Light工具包,我有一个绑定到第一页视图的viewmodel。当用户点击一个按钮时,它会重定向到另一个视图,即第二页 i、 e:

page2comand=newdelegatecommand((obj)=>
Send(新Uri(“/dostufview.xaml”,UriKind.Relative),
Common.CommonResources.GoToDoStuffRequest});
问题是,第二个视图的viewmodel(在我看来)在构造函数中有几个参数,这些参数基本上是第一页上设置的配置的依赖项

i、 e:

public DoStuffViewModel(ICollection<Note> availableNotes, SoundMappers soundType)
{
}
public DoStuffViewModel(ICollection可用节点,声音映射器声音类型)
{
}
问题就在这里。。如何使用用户在第1页上动态选择的数据实例化viewmodel?
我不能使用MVVM light提供的ViewModelLocator模式,因为这些ViewModel没有任何依赖项,它们只是它们自己(或者它们可以从数据库、文件或其他任何地方检索数据,但它们没有任何动态输入数据)。我可以通过视图的构造函数来实现,在那里实例化viewmodel,并将新创建的viewmodel分配给视图的数据源,但我认为这样做不太好。
建议?

我看到您使用Messenger类发送消息,因此您熟悉MVVM灯光下的消息。您必须定义自己的消息类型,该类型应接受第1页中的参数:

    public class Page2ViewModelCreateMessage : MessageBase
{
    public ICollection<Note> AvailableNotes{get;set;}
    public SoundMappers SoundType{get;set;}

    public Page2ViewModelCreateMessage ()
    {

    }

    public Page2ViewModelCreateMessage(ICollection<Note> availableNotes, SoundMappers soundType)
    {
        this.AvailableNotes = availableNotes;
        this.SoundType = soundType;
    }
}
在第2页,您必须注册接收Page2ViewModelCreateMessage类型的消息:

        Messenger.Default.Register<Page2ViewModelCreateMessage>(this, OnPage2ViewModelCreateMessage);
    ..
    public void OnPage2ViewModelCreateMessage(Page2ViewModelCreateMessage message)
    {
        var page2ViewModel = new Page2ViewModel(messsage.AvailableNotes, message.SoundType);
    }   
Messenger.Default.Register(此,在第2页ViewModelCreateMessage上);
..
Page2ViewModelCreateMessage上的公共无效(Page2ViewModelCreateMessage)
{
var page2ViewModel=新的page2ViewModel(message.AvailableNotes,message.SoundType);
}   
如您所见,为了更加清晰,我已将DoStuffViewModel替换为Page2ViewModel

我希望这对你有帮助


注意:我不保证代码会像在记事本中写的那样工作。

我这样做的方式是通过接口拥有一个ViewModels都知道的中央控制器类。然后我将状态设置为该状态,然后让手机为我执行导航。然后,每个ViewModel查询该中心类所需的状态

这对我有很多好处:

  • 它允许我使用非静态视图模型
  • 我可以使用Ninject注入控制器类的具体实现,并将其限定为单例
  • 最重要的是,在进行逻辑删除时,我只需要获取当前的ViewModel和controller类
当我的ViewModel是注册的侦听器时,我遇到了一个消息传递问题,因为我是View First而不是ViewModel First,我被迫使用静态ViewModel引用。否则,ViewModel无法及时创建以接收消息

我将controller类与消息结合使用(它基本上是UI中所有消息的接收者),因此,将来如果我重构,我不需要做太多更改,只需要更改消息的接收者

想想看,controller类也是我的导航接收器——因为我有一些自定义导航代码,可以跳过某些页面上的分页等

以下是我当前设置的一个示例:

public interface IController
{
    Foo SelectedFoo { get; }
}

public class ViewModel
{
    private IController _controller;

    public ViewModel(IController controller)
    {
        _controller = controller;
    }

    private void LoadData()
    {
        // Using selected foo, we load the bars.
        var bars = LoadBars(_controller.SelectedFoo);
    }
}

您可以使用PhoneApplicationService字典保存从第一个事件导航时所需的数据,并在导航到第二个页面时对其进行解析。也可以在ViewModels中使用该数据。 大概是这样的:

 PhoneApplicationService.Current.State["DatatFromFirstPage"] = data;
导航到第二页时:

 if (PhoneApplicationService.Current.State.ContainsKey("DatatFromFirstPage"))
 {
      var dataUsedOnSeconPage= PhoneApplicationService.Current.State["DatatFromFirstPage"];
 }

您可以在整个应用程序中全局使用此数据

尽管您正在注入依赖项,但您的ViewModels不应该从其他地方获取数据,因为这会破坏VM的分离性和可测试性。我们通常让控制器管理虚拟机并将值填充到其中,而不是让虚拟机从外部拖入值。虚拟机应该尽可能无知。只是一个意见。请随意忽略:)让ViewModel需要一些东西是有效的。我看不出给ViewModel提供一个信息源接口与ViewModel依赖之前收到的消息之间有什么区别。至于测试,接口可以模拟。。。因此,它是完全可测试的。+1消息传递是分离ViewModel的一种很好的一致方式,尽管值得说明的是,这是许多可用选项之一。您好。如果我没有错的话,OnPage2ViewModelCreateMessage方法在Page2View上。最后,视图将创建viewmodel,并将其分配给它的DataSource属性。这是正确的吗?我不确定视图是否应该创建viewmodel,尽管消息传递系统确实是发送参数进行创建的系统,而不是实例化参数的视图。嗨,Daniel。你没有错。OnPage2ViewMNodelCreateMessage方法位于Page2View上,并在其中创建ViewModel。另一个选项是对ViewModel使用ViewModelLocator并将其引用到View.DataContext。然而,第一个选项并没有“如此”地破坏MVVM模式。
 PhoneApplicationService.Current.State["DatatFromFirstPage"] = data;
 if (PhoneApplicationService.Current.State.ContainsKey("DatatFromFirstPage"))
 {
      var dataUsedOnSeconPage= PhoneApplicationService.Current.State["DatatFromFirstPage"];
 }