Windows phone 7 处理ViewModel中的OnNavigatedFrom/OnNavigatedTo事件

Windows phone 7 处理ViewModel中的OnNavigatedFrom/OnNavigatedTo事件,windows-phone-7,mvvm-light,Windows Phone 7,Mvvm Light,我正在试图找到一种方法,使我的ViewModel能够在导航页面时保存或恢复页面的状态 我尝试的第一件事是向页面添加EventToCommand行为,但事件(OnNavigatedFrom和OnNavigatedTo)被声明为受保护,EventToCommand看不到要绑定到的事件 接下来,我想尝试使用Messenger类,使用视图代码隐藏中的代码将消息传递给ViewModel: protected override void OnNavigatedFrom(System.Windows.Navi

我正在试图找到一种方法,使我的ViewModel能够在导航页面时保存或恢复页面的状态

我尝试的第一件事是向页面添加EventToCommand行为,但事件(OnNavigatedFrom和OnNavigatedTo)被声明为受保护,EventToCommand看不到要绑定到的事件

接下来,我想尝试使用Messenger类,使用视图代码隐藏中的代码将消息传递给ViewModel:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this);
    base.OnNavigatedFrom(e);
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this); 
    base.OnNavigatedTo(e);
}
受保护的覆盖无效OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
Messenger.Default.Send(此);
基于(e)的导航;
}
受保护的覆盖无效OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
Messenger.Default.Send(此);
基地。导航到(e);
}
但这似乎有两个问题,第一个问题是在代码隐藏页面中包含此代码。其次,ViewModel无法区分OnNavigatedFrom和OnNavigatedTo事件之间的区别,而不必为PhoneApplicationPage对象创建一个set-a包装类(请参见下面的更新)

处理这些事件的最简单的MVVM方式是什么

更新: 我通过发送如下消息解决了第二个问题:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this,"NavigatedFrom");
    base.OnNavigatedFrom(e);
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo"); 
    base.OnNavigatedTo(e);
}
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedFrom", false, (action) => SaveState(action));
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, (action) => RestoreState(action));
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    this.HandleOnNavigatedTo(e);
}
public static void HandleOnNavigatedTo(this Page page, NavigationEventArgs e)
{
    var vm = page.DataContext as IPageNavigationViewModel;
    if (vm == null) return;
    vm.HandleOnNavigatedTo(e);
}
受保护的覆盖无效OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
senger.Default.Send(这是“NavigatedFrom”);
基于(e)的导航;
}
受保护的覆盖无效OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
senger.Default.Send(这是“导航到”);
基地。导航到(e);
}
然后像这样注册他们:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this,"NavigatedFrom");
    base.OnNavigatedFrom(e);
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo"); 
    base.OnNavigatedTo(e);
}
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedFrom", false, (action) => SaveState(action));
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, (action) => RestoreState(action));
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    this.HandleOnNavigatedTo(e);
}
public static void HandleOnNavigatedTo(this Page page, NavigationEventArgs e)
{
    var vm = page.DataContext as IPageNavigationViewModel;
    if (vm == null) return;
    vm.HandleOnNavigatedTo(e);
}
Messenger.Default.Register(这是“NavigatedFrom”,false,(action)=>SaveState(action));
Register(这个“导航到”,false,(action)=>RestoreState(action));

看起来您已经找到了解决问题的方法。我还建议如下:

查看如何使用mvvm工具包中提供的一个消息值,例如:

    NotificationMessage<T>
通知消息
像这样:

    Messenger.Default.Send<NotificationMessage<PhoneApplicationPage>>(
new NotificationMessage<PhoneApplicationPage>(this, "Message"));
Messenger.Default.Send(
新的通知信息(本“信息”);

从代码隐藏处执行命令比处理整个消息传递混乱要干净得多。毕竟,了解视图的DataContext并没有什么错

    protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        viewModel.NavigatedToCommand.Execute(e.Uri);
    }

    ProfileViewModel viewModel
    {
        get
        {
            return this.DataContext as ProfileViewModel;
        }
    }

更新:传入NavigationContext.QueryString可能更有用,因为它已经解析出参数和值。

我想Ryan的意思是,您使用PhoneApplicationPage作为发送的消息,而不是实际的消息

您正在这样做:

Messenger.Default.Send<PhoneApplicationPage>(this);
Messenger.Default.Send(此);
正在发送PhoneApplicationPage类型的消息。您可能不需要将整个PhoneApplicationPage作为消息发送

你可以制作一些导航到/导航自的消息,即

Messenger.Default.Send<NavigatingToMessage>(new NavigatingToMessage());
Messenger.Default.Send(新导航消息());
等等


我相信有一百万种更好的方法可以做到这一点,我只是同意你的想法。就个人而言,我的ViewModel基类有NavigationTo/NavigationFrom方法,我覆盖视图中的各个方法并将它们发送到我的ViewModel

很抱歉,在这个问题上迟到了三年。是的,我还在用Silverlight。好的,我想在
Page
code-behind这样写:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this,"NavigatedFrom");
    base.OnNavigatedFrom(e);
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo"); 
    base.OnNavigatedTo(e);
}
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedFrom", false, (action) => SaveState(action));
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, (action) => RestoreState(action));
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    this.HandleOnNavigatedTo(e);
}
public static void HandleOnNavigatedTo(this Page page, NavigationEventArgs e)
{
    var vm = page.DataContext as IPageNavigationViewModel;
    if (vm == null) return;
    vm.HandleOnNavigatedTo(e);
}
我使用的扩展方法如下:

protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this,"NavigatedFrom");
    base.OnNavigatedFrom(e);
}

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo"); 
    base.OnNavigatedTo(e);
}
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedFrom", false, (action) => SaveState(action));
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, (action) => RestoreState(action));
// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    this.HandleOnNavigatedTo(e);
}
public static void HandleOnNavigatedTo(this Page page, NavigationEventArgs e)
{
    var vm = page.DataContext as IPageNavigationViewModel;
    if (vm == null) return;
    vm.HandleOnNavigatedTo(e);
}
扩展方法意味着
页面
必须具有在
DataContext
中实现IPageNavigationViewModel的视图模型。对我来说,这是一种关注点分离折衷,页面只知道域中最通用的数据类型。该界面如下所示:

using System.Windows.Navigation;

namespace Fox.Silverlight.ViewModels
{
    /// <summary>
    /// Defines View Model members for frame-navigation pages.
    /// </summary>
    public interface IPageNavigationViewModel
    {
        /// <summary>
        /// Handles the <see cref="Page.OnNavigatedTo"/> method in the View Model.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        void HandleOnNavigatedTo(NavigationEventArgs e);

        /// <summary>
        /// Handles the <see cref="Page.OnNavigatedFrom"/> method in the View Model.
        /// </summary>
        /// <param name="e">The <see cref="NavigationEventArgs"/> instance containing the event data.</param>
        void HandleOnNavigatedFrom(NavigationEventArgs e);
    }
}
使用System.Windows.Navigation;
命名空间Fox.Silverlight.ViewModels
{
/// 
///定义框架导航页面的视图模型成员。
/// 
公共界面IPageNavigationViewModel
{
/// 
///处理视图模型中的方法。
/// 
///包含事件数据的实例。
无效HandleOnNavigatedTo(NavigationEventArgs e);
/// 
///处理视图模型中的方法。
/// 
///包含事件数据的实例。
无效HandleOnNavigatedFrom(NavigationEventArgs e);
}
}

我使用问题中更新的答案制作了一个样本:

MainViewModel.xaml.cs:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, ExecuteNavigatedTo);
    }

    // action contains everything you want.
    private void ExecuteNavigatedTo(Page page)
    {
        // example
        bool b = page.NavigationContext.QueryString.ContainsKey("id");
    }
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo");
    base.OnNavigatedTo(e);
}
public类MainViewModel:ViewModelBase
{
公共主视图模型()
{
Messenger.Default.Register(这是“导航到”,false,ExecuteNavigatedTo);
}
//动作包含你想要的一切。
专用无效执行器AvietGatedTo(第页)
{
//范例
bool b=page.NavigationContext.QueryString.ContainsKey(“id”);
}
}
MainViewModel.xaml.cs:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, ExecuteNavigatedTo);
    }

    // action contains everything you want.
    private void ExecuteNavigatedTo(Page page)
    {
        // example
        bool b = page.NavigationContext.QueryString.ContainsKey("id");
    }
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo");
    base.OnNavigatedTo(e);
}
受保护的覆盖无效OnNavigatedTo(NavigationEventArgs e)
{
senger.Default.Send(这是“导航到”);
基地。导航到(e);
}

Am不再使用MVVM灯。我只是在想该执行死刑了。通过ViewModelLocator从视图转到ViewModel