如何使用 DataTemplates 通过 ViewModel-First 方法缓存动态切换的视图

How to cache dynamically switched views by ViewModel-First approach using DataTemplates

(我正在使用 GalaSoft.MvvmLight 框架)

我在 MainWindow.xaml 中有一些观点,我在 运行 时间内根据用户选择在它们之间动态切换。

这些视图使用以下技术与其相应的视图模型绑定:

MainWindow.xaml

...
<Window.Resources>
        <DataTemplate DataType="{x:Type vm:Control1ViewModel}">
            <v:Control1/>
        </DataTemplate>
    ... // Assume there is more then one DataTemplate. Every view has a unique view-model.
</Window.Resources>
...

Control1ViewModel.cs

public class Control1ViewModel : ViewModelBase
{
    ...
}

MainWindow.xaml使用以下技术在上述视图之间切换:

MainWindow.xaml

...
<ContentControl Content="{Binding CurrentView}"/> // This is were the view appears.
...

MainViewModel.cs

public class MainViewModel : ViewModelBase
{
    ...
    private ViewModelBase _currentView;
    public ViewModelBase CurrentView
    {
        get { return _currentView; }
        private set
        {
            _currentView = value;
            base.RaisePropertyChanged("CurrentView");
        }
    }
    ...
}

为了您的方便,我没有添加更多的控件,只是放了一个(Control1)来缩短问题代码部分。如上所述,假设要切换的视图不止一个。

每次 CurrentView 属性 设置一个新的 ViewModelBase 值(例如 Control1ViewModel),WPF会构造绑定视图的新实例DataTemplate可视化树对象,所以旧的会丢失

这意味着我无法在切换视图时缓存视图(例如 Control1)。

我找到的唯一解决方案是 "hardcode" View 及其 ViewModel(使用 DataContext),但按照此解决方案会发生以下情况:

我想知道是否有没有 "hardcoding" 带有视图模型的视图的解决方案,因此我可以保留当前的 ​​ViewModelBase 开关和 ViewModel-First 方法。

你可以有以下方法:

  1. 而不是服用 ContentControl 服用 ItemsControl

<ItemsControl ItemsSource="{Binding Views}" SelectedItem="{Binding CurrentView}"/>

  1. ItemsControlItemsPanel 作为网格,SelectedItem 设置 Z-Index 为 1,其余项目设置 Z-Index 到 0。这样,一次只能看到一个视图,这将覆盖其他视图。

  2. MainViewModel中的两个属性。 ObservableCollection<ViewModelBase> 类型的 ViewsViewModelBase 类型的 CurrentView 并将其分别与 ItemsControlsItemsSourceSelectedItem 绑定。

现在,当您想打开一个视图时,创建一个 ViewModel,将其添加到 Views 列表并将其设置为 CurrentView。如果它已经存在于列表中,只需将其设置为 CurrentView。

如果您希望它永远关闭,还提供一个关闭按钮。也就是说,如果您要关闭它,它将从列表中删除并且不会被缓存。

这就像您在 window 中打开了不同的视图一样,您可以在它们之间切换。如果您愿意,可以关闭视图。

编辑: 见以下代码:

            <ItemsControl ItemsSource="{Binding Views}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <Grid Margin="10,10,0,10">
                        </Grid>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>

                <ItemsControl.ItemContainerStyle>
                    <Style>
                        <Setter Property="Grid.Opacity" Value="{Binding ZIndex}"/>
                        <Setter Property="Grid.ZIndex" Value="{Binding ZIndex}"/>
                    </Style>
                </ItemsControl.ItemContainerStyle>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <ContentControl Content="{Binding}"/>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

在这里您可以看到,在您的 ViewModel 中,您必须有一个 属性 ZIndex,它将用于在顶部显示当前视图。因此,无论何时您想要显示视图,只需将 ViewModelZIndex 属性 设置为 1 并将重置视图重置为 0.