处理ViewModel中的OnNavigatedFrom / OnNavigatedTo事件

时间:2010-07-27 21:43:01

标签: windows-phone-7 mvvm-light

我正试图找出一种方法让我的ViewModel在页面导航时从To或To处理保存或恢复页面的状态。

我尝试的第一件事是向页面添加EventToCommand行为,但事件(OnNavigatedFrom和OnNavigatedTo)被声明为protected,而EventToCommand没有看到要绑定的事件。

接下来我想我会尝试使用Messenger类使用View后面代码中的代码将消息传递给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);
}

但这似乎有两个问题,首先是在代码隐藏页面中使用此代码。其次,ViewModel无法区分OnNavigatedFrom和OnNavigatedTo事件,而无需为PhoneApplicationPage对象创建一个包装类(请参阅下面的更新)。

处理这些事件的MVVM-Light最友好的方式是什么?

更新: 通过像这样发送消息,我能够解决第二个问题:

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));

5 个答案:

答案 0 :(得分:5)

从代码后面执行命令比通过整个消息传递混乱更清晰。毕竟知道它的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可能更有用,因为它已经解析了参数和值。

答案 1 :(得分:3)

很抱歉这个问题迟到了三年。是的,我还在使用Silverlight。好吧,我想在Page代码隐藏中编写它,如下所示:

// 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);
}

扩展方法意味着Page必须具有在DataContext中实现IPageNavigationViewModel的视图模型。对我来说,这是一个关注点分离的妥协,其中Page只知道域中最通用的数据类型。这个界面:

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);
    }
}

答案 2 :(得分:1)

看起来您已经解决了问题。我还建议如下:

使用mvvm-toolkit中提供的消息值之一,例如:

    NotificationMessage<T>

像这样:

    Messenger.Default.Send<NotificationMessage<PhoneApplicationPage>>(
new NotificationMessage<PhoneApplicationPage>(this, "Message"));

答案 3 :(得分:0)

我认为Ryan所得到的是,您使用PhoneApplicationPage作为正在发送的消息,而不是实际的消息。

你这样做:

Messenger.Default.Send<PhoneApplicationPage>(this);

正在发送PhoneApplicationPage类型的消息。您可能不需要将整个PhoneApplicationPage作为消息发送。

您可以为NavigatingTo / NavigatingFrom制作一些消息,即

Messenger.Default.Send<NavigatingToMessage>(new NavigatingToMessage());

我敢肯定有一百万种更好的方法可以做到这一点,我只是跟你如何设置。就个人而言,我的ViewModelBase类有NavigatingTo / NavigatingFrom方法,我覆盖视图中的相应方法并将它们发送到我的ViewModel。

答案 4 :(得分:0)

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

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");
    }
}

MainViewModel.xaml.cs:

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    Messenger.Default.Send<PhoneApplicationPage>(this, "NavigatedTo");
    base.OnNavigatedTo(e);
}