Каков наилучший способ переключения представлений / пользовательских контролей в MVVM-light и WPF? - PullRequest
24 голосов
/ 24 мая 2011

Я относительно новичок в WPF и MVVM, и самое сложное, что я нашел, это как просто переключить пользовательский контроль или представление в приложении.

В winforms, чтобы элемент управления сам удалялся, вы бы просто сказали это.Parent.Controls.Remove (this);

В WPF нет универсального родительского элемента управления, вам придется типизировать его к определенному типу (то есть Grid), а затем удалить его.

Это также, кажется, нарушает архитектуру MVVM. Я также попробовал шаблоны данных и средства представления контента, которые работают хорошо, за исключением того факта, что я не могу изменить текст данных datacontext из кода, так как он всегда является viewmodellocator.

Являются ли страницы приемлемым способом сделать это в WPF сейчас? Что если у меня есть сетка с пользовательским контролем использования, и я хочу переключить ее на основе некоторой переменной в viewModel? Кажется, что самые простые задачи не могут быть легко выполнены в WPF.

1 Ответ

34 голосов
/ 24 мая 2011

Вы можете сделать это в родительском ViewModel.

Например, если ваша страница (назовите ее PageViewModel) имеет два просмотра (ViewModelA и ViewModelB), у вас будет свойство наPageViewModel называется CurrentView, и это будет определять, какой вид виден.Если для PageViewModel.CurrentView задан экземпляр ViewModelA, то DataTemplate ViewA используется для рисования содержимого.Когда для него установлен экземпляр ViewModelB, отображается DataTemplate ViewB.

<DataTemplate DataType="{x:Type local:PageViewModel}">
    <ContentControl Content="{Binding CurrentView}" />
</DataTemplate>

<DataTemplate DataType="{x:Type local:ViewModelA}">
    <TextBlock Text="I'm ViewModelA" />
</DataTemplate>

<DataTemplate DataType="{x:Type local:ViewModelB}">
    <TextBlock Text="I'm ViewModelB" />
</DataTemplate>

Было бы идеально вызывать команду переключения представлений из родительского представления (в данном случае DataTemplate для PageViewModel), однако, если вы хотите переключить представления из ViewModelA / B, вы можете либо подключить событие вручную, когда объекты будут созданы (CurrentView.ChangeViewCommand = this.ChangeViewCommand), либо заглянуть в систему обмена сообщениями.MVVM Light имеет простой Messenger класс, который я нашел довольно простым в использовании, или Prism имеет более продвинутый EventAggregator

Если вы хотите переключать виды для одной и той же ViewModel, я бы порекомендовал свойство Modeкоторый используется, чтобы определить, какой вид использовать.Например:

<DataTemplate x:Key="ViewA" DataType="{x:Type local:MyViewModel}">
    <TextBlock Text="I'm ViewModelA" />
</DataTemplate>

<DataTemplate x:Key="ViewB" DataType="{x:Type local:MyViewModel}">
    <TextBlock Text="I'm ViewModelB" />
</DataTemplate>

<DataTemplate DataType="{x:Type local:MyViewModel}">
    <ContentControl Content="{Binding }">
        <ContentControl.Style>
            <Style TargetType="{x:Type ContentControl}">
                <Setter Property="ContentTemplate" Value="{StaticResource ViewA}" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Mode}" Value="2">
                        <Setter Property="ContentTemplate" Value="{StaticResource ViewB}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </ContentControl.Style>
    </ContentControl>
</DataTemplate>

РЕДАКТИРОВАТЬ

Я действительно вижу, что такого рода вопросы часто возникают, поэтому выложили что-то об этом здесь есливсем интересно

...