我正试图找出一种方法让我的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));
答案 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);
}