Обработка событий OnNavigatedFrom / OnNavigatedTo в ViewModel - PullRequest
10 голосов
/ 28 июля 2010

Я пытаюсь найти способ, с помощью которого моя ViewModel может сохранять или восстанавливать состояние страницы при переходе по странице От или К.

Первое, что я попробовал, - добавить поведение EventToCommand кстраницы, но события (OnNavigatedFrom и OnNavigatedTo) объявлены защищенными, а EventToCommand не видит события для привязки.

Затем я подумал, что попробую использовать класс Messenger для передачи сообщения в ViewModel с использованием кодав коде View:

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 ]

5 голосов
/ 01 июня 2011

Выполнение команды из кода позади намного чище, чем прохождение всего беспорядка обмена сообщениями.В конце концов, нет ничего плохого в том, что представление знает о его 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, вероятно, более полезна, поскольку она уже анализирует параметры и значение.

3 голосов
/ 06 апреля 2013

Извините, что опоздал на три года на этот вопрос.Да, я все еще использую 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);
}

Метод расширения подразумевает, что1008 * должен иметь модель представления, которая реализует IPageNavigationViewModel в DataContext.Для меня это компромисс между разделением проблем, когда Страница знает только о самых общих типах данных в Домене.Это интерфейс:

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);
    }
}
1 голос
/ 04 августа 2010

Похоже, у вас уже есть решение вашей проблемы.Я бы также предложил следующее:

Посмотрите на использование одного из значений сообщений, предоставляемых в наборе инструментов mvvm, например:

    NotificationMessage<T>

Например:

    Messenger.Default.Send<NotificationMessage<PhoneApplicationPage>>(
new NotificationMessage<PhoneApplicationPage>(this, "Message"));
0 голосов
/ 02 апреля 2015

Я делаю образец, используя обновленный ответ внутри вопроса:

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);
}
0 голосов
/ 14 июля 2011

Я думаю, что Райан понял, что вы используете PhoneApplicationPage в качестве отправляемого сообщения вместо реального сообщения.

Вы делаете это:

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

, который отправляет сообщение типа PhoneApplicationPage. Возможно, вам не нужно отправлять весь PhoneApplicationPage в качестве сообщения.

Вы можете сделать несколько сообщений для NavigatingTo / NavigatingFrom, например.

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

и т.д.

Я уверен, что есть миллион лучших способов сделать это, я просто согласился с тем, как вы это настроили. Лично мой класс ViewModelBase имеет методы NavigatingTo / NavigatingFrom, и я переопределяю соответствующие методы в представлении и отправляю их моему ViewModel.

...