Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
268 views
in Technique[技术] by (71.8m points)

c# - Changing the View for a ViewModel

I am trying to implement the MVVM design patern for mt WPF application. In order to connect the view to the viewmodels, I use a ResourceDictionary (used in Application.Resources), that looks like

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

The view models are then simply put into content presenters to display them.

Now, when the user presses a button, I'd like to display SampleViewModel using a different view. How do I change the data template used for SampleViewModel?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Less words more code. As far as you said, you have the class SampleViewModel. I added the property Title for demonstration and ViewType for identifying the correct view:

public enum ItemViewType { View1, View2 };

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

The DataTemplateSelector for two views depending on the ViewType property:

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 code:

<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>

The main part is in the class MainViewModel where I've put the logic for switching views:

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");
        }
    }
}

The SwitchViewCommand can be any type of command, I use the command from the mvvmlight library.

Inside the handler of the command I change the type of viewmodel and update the property ItemViewModel in a tricky way because a ContentControl refreshes a view only if to change the Content property, and this property will not be changed unless you set a reference to different object.

I mean, even the code this.ItemViewModel = this.itemViewModel will not change the view. It's strange, but the workaround doesn't require much work.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...