Реализовать смену UserControl в главном окне WPF MVVM [дубликат]

304
24 января 2018, 12:40

На данный вопрос уже ответили:

  • Отображение разного содержимого в одном окне WPF + MVVM 1 ответ

Каким образом можно в главном окне подсовывать нужный UserControl без изменения параметра видимости. К примеру есть окно при запуске отображается FirstUserControl потом при каком нибудь событие (например нажатие на кнопку) FirstUcerControl отрабатывает (закрывается), и отображается новый SecondUserControl.

Answer 1

Для этого используется DataTemplateSelector. Я покажу небольшой пример.

Допустим, у меня есть VM-классы CarVm и UserVm, которые я хочу отображать в одном окне, я набросал такую простую MainVm:

class MainVm : Vm
{
    object innerVm;
    public object InnerVm
    {
        get => innerVm;
        set => Set(ref innerVm, value, nameof(InnerVm));
    }
    public DelegateCommand ChangeCommand { get; }
    public MainVm()
    {
        ChangeCommand = new DelegateCommand(_ => InnerVm = (InnerVm is UserVm) ? (object)new CarVm() : (object)new UserVm());
    }
}

Тут всё просто, по команде у нас меняется свойство InnerVm, причем оно каждый раз будет менять тип.

Займемся разметкой, я в Grid добавлю ContentPresenter для отображения InnerVm и кнопку для вызова команды:

<Grid Margin="5">
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition Height="Auto"/>
    </Grid.RowDefinitions>
    <ContentPresenter Content="{Binding InnerVm}">
    </ContentPresenter>
    <Button Grid.Row="1" Content="Change"
            HorizontalAlignment="Center"
            Command="{Binding ChangeCommand}"/>
</Grid>

Теперь нам для каждого отображаемого типа необходимо реализовать DataTemplate-разметку, я добавлю ее в ресурсы ContentPresenter:

        <ContentPresenter.Resources>
            <DataTemplate x:Key="UserTemplate">
                <StackPanel d:DataContext="{d:DesignInstance Type=c:UserVm}">
                    <TextBlock Text="{Binding Name}"/>
                    <TextBlock Text="{Binding Age}"/>
                </StackPanel>
            </DataTemplate>
            <DataTemplate x:Key="CarTemplate">
                <StackPanel d:DataContext="{d:DesignInstance Type=c:CarVm}">
                    <TextBlock Text="{Binding Model}"/>
                    <TextBlock Text="{Binding MaxSpeed}"/>
                </StackPanel>
            </DataTemplate>
        </ContentPresenter.Resources>

Теперь пишем класс-наследник DataTemplateSelector:

class MyTemplateSelector : DataTemplateSelector
{
    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var fe = (FrameworkElement)container;
        if (item is UserVm) return fe.FindResource("UserTemplate") as DataTemplate;
        if (item is CarVm) return fe.FindResource("CarTemplate") as DataTemplate;
        return null;
    }
}

Создаем экземпляр этого класса в ресурсах Grid:

    <Grid.Resources>
        <c:MyTemplateSelector x:Key="MyTemplateSelector"/>
    </Grid.Resources>

И подключаем его к нашему ContentPresenter: ContentTemplateSelector="{StaticResource MyTemplateSelector}"

Готово!

READ ALSO
(C#, TLS) PseudoRandomFunction (PRF)

(C#, TLS) PseudoRandomFunction (PRF)

ЗдравствуйтеПишу TLS сервер

185
Отображение img и работа src в js

Отображение img и работа src в js

На клиенте в браузере выводятся изображения фотографий небольших размеров, например, 20 штук в формате :

200