Как использовать MVVM ViewModel для изменения содержимого в представлении на основе события ListView SelectionChanged - PullRequest
0 голосов
/ 23 июня 2019

Я хочу создать приложение UWP с навигацией по списку, чей выбранный элемент определяет содержимое кадра.Когда выбор изменяется, содержимое кадра должно измениться.Я нашел пример того, как это сделать (метод 1 ниже), но он использует обработчики событий в коде позади.Я хочу изучить MVVM с этим проектом и, таким образом, хочу использовать MVVM-решение этой проблемы.Я новичок в MVVM, и мое текущее понимание состоит в том, что для того, чтобы отделить View от ViewModel, ViewModels не должен ссылаться на что-то определенное для View.Это правильное понимание?Единственный способ, с помощью которого я могу использовать ViewModel для изменения представления фрейма, - это в основном переместить код обработчика события в ViewModel и передать фрейм в конструктор (метод 2 ниже).Но это нарушает мое понимание связи ViewModel с View, поскольку ViewModel ссылается на конкретные экземпляры вещей в View;кроме того, это кажется бессмысленным расходом средств и может принести очень мало пользы для организации.

Как бы вы реализовали решение MVVM для этой проблемы?Или это тот случай, когда лучше использовать обработчики событий?

МЕТОД 1 - Обработчик событий: Этот код основан на примере, предоставленном Microsoft.(Вот ссылка на соответствующий код: https://github.com/microsoft/Windows-universal-samples/tree/master/Samples/Playlists/cs)

public sealed partial class MainPage : Page
{
    List<Scenario> scenarios = new List<Scenario>
    {
        new Scenario() { Title = "Scenario 1", ClassType = typeof(Scenario1) },
        new Scenario() { Title = "Scenario 2", ClassType = typeof(Scenario2) }
    };

    public MainPage()
    {
        this.InitializeComponent();
    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        ScenarioControl.ItemsSource = scenarios;
    }

    private void ScenarioControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        ListBox scenarioListBox = sender as ListBox;
        Scenario s = scenarioListBox.SelectedItem as Scenario;
        if (s != null)
        {
            ScenarioFrame.Navigate(s.ClassType);
        }
    }
}

public class Scenario
{
    public string Title { get; set; }
    public Type ClassType { get; set; }

    public override string ToString()
    {
        return Title;
    }
}

<!-- MainPage.xaml -->
<Grid>
    <SplitView x:Name="Splitter" IsPaneOpen="True" DisplayMode="Inline">
        <SplitView.Pane>
            <RelativePanel>
                <ListBox x:Name="ScenarioControl" SelectionChanged="ScenarioControl_SelectionChanged"/>
            </RelativePanel>
        </SplitView.Pane>
        <RelativePanel>
            <Frame x:Name="ScenarioFrame" />
        </RelativePanel>
    </SplitView>
</Grid>

МЕТОД 2 - MVVM (?):

<!-- MainPage.xaml -->
<Grid>
    ...
    <ListBox x:Name="ScenarioControl" SelectionChanged="{x:Bind MyViewModel.SwitchScenario}"/>
    ...
</Grid>
// MainPage.xaml.cs
...
    public MainPage()
    {
        this.InitializeComponent();
        MyViewModel = new MyViewModel(ScenarioFrame);
    }
...
    MyViewModel MyViewModel { get; set; }
}

// MyViewModel.cs
public class MyViewModel
{
    public MyViewModel(Frame scenarioFrame)
    {
        ScenarioFrame = scenarioFrame;
    }

    public void SwitchScenario(object sender, SelectionChangedEventArgs e)
    {
        ListBox scenarioListBox = sender as ListBox;
        Scenario s = scenarioListBox.SelectedItem as Scenario;
        if (s != null)
        {
            ScenarioFrame.Navigate(s.ClassType);
        }
    }

    public Frame ScenarioFrame { get; set; }
}

Ответы [ 2 ]

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

Как бы вы реализовали решение MVVM для этой проблемы?Или это тот случай, когда лучше использовать обработчики событий?

Для реализации навигации MVVM вы можете обратиться к рабочему процессу Template 10 и Template Studio .

В шаблоне 10 он связывает событие Click с методом навигации.

<controls:PageHeader x:Name="pageHeader" RelativePanel.AlignLeftWithPanel="True"
                     RelativePanel.AlignRightWithPanel="True"
                     RelativePanel.AlignTopWithPanel="True" Text="Main Page">

    <!--  secondary commands  -->
    <controls:PageHeader.SecondaryCommands>
        <AppBarButton Click="{x:Bind ViewModel.GotoSettings}" Label="Settings" />
        <AppBarButton Click="{x:Bind ViewModel.GotoPrivacy}" Label="Privacy" />
        <AppBarButton Click="{x:Bind ViewModel.GotoAbout}" Label="About" />
    </controls:PageHeader.SecondaryCommands>

</controls:PageHeader>

ViewModel

 public void GotoDetailsPage() =>
     NavigationService.Navigate(typeof(Views.DetailPage), Value);

 public void GotoSettings() =>
     NavigationService.Navigate(typeof(Views.SettingsPage), 0);

В Template Studio этоперемещается с помощью NavHelper класса.

<winui:NavigationViewItem x:Uid="Shell_Main" Icon="Document" helpers:NavHelper.NavigateTo="views:MainPage" />
<winui:NavigationViewItem x:Uid="Shell_Blank" Icon="Document" helpers:NavHelper.NavigateTo="views:BlankPage" />
<winui:NavigationViewItem x:Uid="Shell_MediaPlayer" Icon="Document" helpers:NavHelper.NavigateTo="views:MediaPlayerPage" />
<winui:NavigationViewItem x:Uid="Shell_WebView" Icon="Document" helpers:NavHelper.NavigateTo="views:WebViewPage" />


<ic:EventTriggerBehavior EventName="ItemInvoked">
                <ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemInvokedCommand}" />
            </ic:EventTriggerBehavior>

ViewModel

private void OnItemInvoked(WinUI.NavigationViewItemInvokedEventArgs args)
{
    if (args.IsSettingsInvoked)
    {
        NavigationService.Navigate(typeof(SettingsPage));
        return;
    }

    var item = _navigationView.MenuItems
                    .OfType<WinUI.NavigationViewItem>()
                    .First(menuItem => (string)menuItem.Content == (string)args.InvokedItem);
    var pageType = item.GetValue(NavHelper.NavigateToProperty) as Type;
    NavigationService.Navigate(pageType);
}
0 голосов
/ 23 июня 2019

Вам понадобится PropertyChangedNotification, когда ваше свойство модели изменится - все, что связано со свойством модели, будет обновлено автоматически.

Также Bindings.Update () иногда является вашим другом.

И если у вас будут View и ViewModel, вам нужно будет установить DataContext вашего View на экземпляр ViewModel или Model, к которой вы привязываетесь.

...