处理 ViewModel 中的 OnNavieratedFrom / OnNavieratedTo 事件

发布于 2024-09-12 05:05:57 字数 1543 浏览 3 评论 0原文

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

我尝试的第一件事是将 EventToCommand 行为添加到页面,但事件(OnNavieratedFrom 和 OnNavigedTo)被声明为受保护,并且 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);
}

但这似乎有两个问题,首先是将此代码放在代码隐藏页面中。其次,如果不必为 PhoneApplicationPage 对象创建一组包装器类,ViewModel 就无法区分 OnNavieratedFrom 和 OnNavieratedTo 事件(请参阅下面的更新)。

处理这些事件对 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));

I am trying to figure out a way for my ViewModel to handle saving or restore the page's state when the page is navigated From or To.

The first thing I tried was to add an EventToCommand behavior to the page, but the events (OnNavigatedFrom and OnNavigatedTo) are declared protected and the EventToCommand does not see the events to bind to.

Next I thought I would try using the Messenger class to pass a message to the ViewModel using code in the View's code behind:

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

But this seems to have two issues, first is having this code in the code behind page. Second, the ViewModel cannot tell the difference between the OnNavigatedFrom and the OnNavigatedTo events without having to create a set a wrapper classes for the PhoneApplicationPage object (see UPDATE below).

What is the most MVVM-Light friendly way to handle these events?

UPDATE:
I was able to resolve the second issue by Sending the Messages like this:

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

and Registering them like this:

Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedFrom", false, (action) => SaveState(action));
Messenger.Default.Register<PhoneApplicationPage>(this, "NavigatedTo", false, (action) => RestoreState(action));

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

喜爱纠缠 2024-09-19 05:05:57

从代码后面执行命令比遍历整个消息传递要干净得多。毕竟,视图了解其 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可能更有用,因为它已经解析出参数和值。

Executing a command from code behind is far cleaner than going through the whole messaging mess. After all there's nothing wrong with the view knowing about its 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;
        }
    }

Update: Passing in NavigationContext.QueryString is probably more useful, since it already parses out the parameters and value.

时光礼记 2024-09-19 05:05:57

抱歉,这个问题迟到了三年。是的,我仍在使用 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。对我来说,这是一种关注点分离的妥协,其中页面仅了解域中最通用的数据类型。这是界面:

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

Sorry for being three years late to this question. Yes, I'm still using Silverlight. Okay I want to write it in Page code-behind like this:

// Executes when the user navigates to this page.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    this.HandleOnNavigatedTo(e);
}

I am using an extension method like this:

public static void HandleOnNavigatedTo(this Page page, NavigationEventArgs e)
{
    var vm = page.DataContext as IPageNavigationViewModel;
    if (vm == null) return;
    vm.HandleOnNavigatedTo(e);
}

The extension method implies that the Page must have a View Model that implements IPageNavigationViewModel in DataContext. For me, this is a separation-of-concerns compromise where the Page knows only about the most general-purpose data types in the Domain. This the interface:

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);
    }
}
那小子欠揍 2024-09-19 05:05:57

看来您已经找到了解决问题的方法。我还建议执行以下操作:

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

    NotificationMessage<T>

像这样:

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

Looks like you have a solution to your problem already. I would also suggest the following:

Look at using one of the message values provided in the mvvm-toolkit, such as:

    NotificationMessage<T>

Like this:

    Messenger.Default.Send<NotificationMessage<PhoneApplicationPage>>(
new NotificationMessage<PhoneApplicationPage>(this, "Message"));
傲影 2024-09-19 05:05:57

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

您正在执行以下操作:

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

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

您可以为 NavigatingTo / NavigatingFrom 创建一些消息,即。

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

我确信有一百万种更好的方法可以做到这一点

,我只是按照你的设置方式进行。就我个人而言,我的 ViewModelBase 类具有 NavigatingTo/NavigatingFrom 方法,我重写视图中的相应方法并将它们发送到我的 ViewModel。

I think what Ryan was getting at, was the fact that you're using the PhoneApplicationPage as the message that is being sent, instead of an actual message.

You're doing this:

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

which is sending a message of type PhoneApplicationPage. You probably don't need to send the entire PhoneApplicationPage as the message.

You could make some messages for NavigatingTo / NavigatingFrom, ie.

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

etc.

I'm sure there are a million better ways to do this, I was just going along with how you had set things up. Personally, my ViewModelBase class has NavigatingTo/NavigatingFrom methods and I override the respective methods in the View and send them to my ViewModel.

心病无药医 2024-09-19 05:05:57

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

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

I make a sample using the updated answer inside the question :

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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文