Изменение вида для модели представления

Я пытаюсь реализовать шаблон дизайна MVVM для приложения mt WPF. Чтобы подключить вид к моделям вида, я использую ResourceDictionary (используется в Application.Resources), это выглядит

<DataTemplate DataType={x:Type viewmodel:SampleViewModel}>
    <view:SampleView1 />
</DataTemplate>

Модели представлений затем просто помещаются в предъявители контента для их отображения.

Теперь, когда пользователь нажимает кнопку, я хотел бы отобразить SampleViewModel используя другой взгляд. Как изменить шаблон данных, используемый для SampleViewModel?

3 ответа

Решение

Меньше слов, больше кода. Насколько вы сказали, у вас есть класс SampleViewModel, Я добавил недвижимость Title для демонстрации и ViewType для определения правильного вида:

public enum ItemViewType { View1, View2 };

public class SampleViewModel 
{
    public string Title { get; set; }
    public ItemViewType ViewType { get; set; }
}

DataTemplateSelector для двух просмотров в зависимости от ViewType имущество:

class ItemViewTemplateSelector : DataTemplateSelector
{
    public DataTemplate View1Template { get; set; }
    public DataTemplate View2Template { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        var vm = item as SampleViewModel;
        if (vm == null)
            return null;

        switch (vm.ViewType)
        {
            case ItemViewType.View1:
                return View1Template;
            case ItemViewType.View2:
                return View2Template;
        }

        return null;
    }
}

XAML код:

<Window.Resources>
    <DataTemplate x:Key="view1Template">
        <TextBlock Text="{Binding Title}" Foreground="Red"/>
    </DataTemplate>
    <DataTemplate x:Key="view2Template">
        <TextBox Text="{Binding Title}" />
    </DataTemplate>
    <local:ItemViewTemplateSelector x:Key="viewTemplateSelector"
                                    View1Template="{StaticResource view1Template}"
                                    View2Template="{StaticResource view2Template}"/>
</Window.Resources>

<Window.DataContext>
    <local:MainViewModel/>
</Window.DataContext>

<StackPanel>
    <Button Content="ChangeView" HorizontalAlignment="Center" Command="{Binding SwitchViewCommand}"/>
    <ContentControl  Content="{Binding ItemViewModel}" ContentTemplateSelector="{StaticResource viewTemplateSelector}"/>
</StackPanel>

Основная часть в классе MainViewModel где я положил логику для переключения видов:

public class MainViewModel : ViewModelBase
{
    public MainViewModel()
    {
        this.ItemViewModel = new SampleViewModel { Title = "Some title", ViewType = ItemViewType.View1 };

        this.SwitchViewCommand = new RelayCommand(() =>
        {
            this.ItemViewModel.ViewType = this.ItemViewModel.ViewType == ItemViewType.View1
                                            ? ItemViewType.View2
                                            : ItemViewType.View1;
            //The magic senquence of actions which forces a contentcontrol to change the content template
            var copy = this.ItemViewModel;
            this.ItemViewModel = null;
            this.ItemViewModel = copy;
        });
    }

    public RelayCommand SwitchViewCommand { get; set; }

    private SampleViewModel itemViewModel;

    public SampleViewModel ItemViewModel
    {
        get { return itemViewModel; }
        set
        {
            itemViewModel = value;
            RaisePropertyChanged("ItemViewModel");
        }
    }
}

SwitchViewCommand может быть команда любого типа, я использую команду из библиотеки mvvmlight.

Внутри обработчика команды я меняю тип viewmodel и обновляю свойство ItemViewModel хитро, потому что ContentControl обновляет представление, только если изменить свойство Content, и это свойство не будет изменено, если вы не установите ссылку на другой объект.

Я имею в виду, даже код this.ItemViewModel = this.itemViewModel не изменит вид. Это странно, но обходной путь не требует большой работы.

Вы можете достичь этого разными способами, в зависимости от архитектуры, которую вы хотите.

  • Вы можете написать собственный DataTemplateSelector и использовать его в ContentControl.ContentTemplateSelector и выбрать эти два шаблона соответствующим образом
  • Если этот шаблон изменения представления происходит во многих разных местах и ​​более частом UX, я бы также рекомендовал переключать эти два представления с помощью DataTemplate.DataTrigger на основе свойства в SampleViewModel [я предполагаю, что у вас может быть отличительное свойство в ViewModel для знаю это состояние]

Вы можете переопределить отображение, разместив аналогичный ресурс ниже в дереве. Поскольку WPF разрешит ресурс путем поиска вверх, такое переопределение заменит существующее сопоставление.

Другие вопросы по тегам