Передача параметра через оболочку при навигации в приложении UWP с использованием MVVM - PullRequest
1 голос
/ 25 июня 2019

Начали изучать разработку UWP, создав приложение Windows Template Studio с горизонтальной навигацией тип проекта , MVVM Light шаблон проектирования и две пустые страницы (MainPage и StatsPage).

В главной странице у меня есть список элементов, и я хочу показать статистику выбранного элемента в StatsPage, когда пользователь нажимает соответствующую NavigationViewItem. В моих приложениях wpf я установил бы RelayCommand с параметром команды для кнопки в главном представлении, а в модели представления, вызвал метод команды с параметром / arg, чтобы открыть представление Stats с правильной информацией. В созданном приложении Template Studio NavigationViewItem в ShellPage вызывает OnItemInvoked() в своей виртуальной машине, которая не знает о выборе в представлении MainPage.

<winui:NavigationView.MenuItems>
  <winui:NavigationViewItem x:Uid="Shell_Main" helpers:NavHelper.NavigateTo="LG_Ess.ViewModels.MainViewModel" />
  <winui:NavigationViewItem x:Uid="Shell_Stats" helpers:NavHelper.NavigateTo="LG_Ess.ViewModels.StatsViewModel" />
</winui:NavigationView.MenuItems>
  <i:Interaction.Behaviors>
    <ic:EventTriggerBehavior EventName="ItemInvoked">
      <ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemInvokedCommand}" />
    </ic:EventTriggerBehavior>
  </i:Interaction.Behaviors>

Как передать выбранный элемент MainPage в качестве параметра StatsPage через ShellPage NavigationViewItem? Я мог бы, вероятно, решить это, добавив кнопку на мою MainPage и скрыв навигацию по Shell, но я бы предпочел сделать это в стиле Template Studio.

Дальнейшие исследования показывают, что ShellViewModel, по-видимому, является DataContext по умолчанию для всех страниц, созданных Template Studio. На своих страницах я установил контекст данных для автоматически сгенерированных моделей просмотра, добавив:

<Page.DataContext>
  <local:{PageName}ViewModel/>
</Page.DataContext>

Так что, похоже, я могу либо иметь одну ViewModel и обрабатывать страницы как UserControls, либо отображать DataContext для каждой страницы в свой собственный ViewModel, а также выполнять танец ViewModelLocator для доступа к свойствам из одной виртуальной машины в другой.

1 Ответ

0 голосов
/ 27 июня 2019

Так что, похоже, я могу либо иметь одну ViewModel и обрабатывать страницы как UserControls, либо сопоставлять DataContext для каждой страницы с ее собственным ViewModel, и выполнять некоторые танцы ViewModelLocator для доступа к свойствам из одной виртуальной машины в другой.

Правильно. Вы можете определить соответствующее свойство SelectedStats в вашей MainViewModel и сделать привязку SelectedItem вашего ListView к этому свойству и установить Mode=TwoWay. Затем в StatsPage вы можете использовать EventTriggerBehavior для привязки LoadedCommand в StatsViewModel, например ShellPage. В StatsViewModel вы можете получить выбранный элемент, вызвав ViewModelLocator.Current.MainViewModel.SelectedStats.

См. Мой простой пример кода:

<!--MainPage.xaml-->
<ListView ItemsSource="{x:Bind ViewModel.list}" SelectedItem="{x:Bind ViewModel.SelectedStats,Mode=TwoWay}">
</ListView>
public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        list = new ObservableCollection<string>();
        list.Add("string1");
        list.Add("string2");
        list.Add("string3");
    }

    public ObservableCollection<string> list { get; set; }

    private object _SelectedStats;

    public object SelectedStats
    {
        get { return _SelectedStats; }
        set
        {
            if (_SelectedStats != value)
            {
                _SelectedStats = value;
                RaisePropertyChanged("SelectedStats");
            }
        }
    }
}
<!--StatsPage.xaml-->
<i:Interaction.Behaviors>
    <ic:EventTriggerBehavior EventName="Loaded">
        <ic:InvokeCommandAction Command="{x:Bind ViewModel.LoadedCommand}" />
    </ic:EventTriggerBehavior>
</i:Interaction.Behaviors>
public class StatsViewModel : ViewModelBase
{
    public StatsViewModel()
    {
    }

    private ICommand _LoadedCommand;
    public ICommand LoadedCommand => _LoadedCommand ?? (_LoadedCommand = new RelayCommand(LoaedAsync));

    private async void LoaedAsync()
    {
        var selectedObject = ViewModelLocator.Current.MainViewModel.SelectedStats;
        //TODO:...
        await Task.CompletedTask;
    }
}
...