(我正在使用 GalaSoft.MvvmLight
框架)
我在 MainWindow.xaml
中有一些 View ,我在运行时通过用户选择在它们之间动态切换。
这些 View 使用以下技术绑定(bind)到它们相应的 View 模型:
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
使用以下技术在上述 View 之间切换:
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
)来缩短问题代码部分。如上所述,假设要切换的 View 不止一个。
每次 CurrentView
属性设置一个新的 ViewModelBase
值(例如 Control1ViewModel
),WPF将构造绑定(bind) View DataTemplate
可视化树对象 的新实例,因此旧实例将丢失。
这意味着我无法在切换 View 时缓存 View (例如 Control1
)。
我找到的唯一解决方案是用它的 ViewModel(使用 DataContext)“硬编码”View,但是按照这个解决方案会发生以下情况:
- 我正在打破 ViewModel-First 方法。
- 为了不破坏完整的 MVVM,我必须更改
CurrentView
签名并将其移动到我的MainWindow.xaml
的代码后面。 - 我没有切换
ViewModelBase
类型,而是切换具体控件。
我想知道是否有不使用 View 模型“硬编码” View 的解决方案,这样我就可以保留当前的 ViewModelBase
开关和 ViewModel-First 方法。
最佳答案
你可以有以下方法:
- 而不是服用
ContentControl
拿个ItemsControl
<ItemsControl ItemsSource="{Binding Views}" SelectedItem="{Binding CurrentView}"/>
取
ItemsPanel
的ItemsControl
作为网格和SelectedItem
设置Z-Index
到 1 和其余项目集Z-Index
到 0。这样,一次只有一个 View 可见,它会覆盖其他 View 。取
MainViewModel
中的两个属性.Views
类型ObservableCollection<ViewModelBase>
和CurrentView
类型ViewModelBase
并将其与ItemsControls
绑定(bind)的ItemsSource
和SelectedItem
分别。
现在,当您想要打开一个 View 时,创建一个 ViewModel,将其添加到 View 列表并将其设置为 CurrentView。如果它已经存在于列表中,只需将其设置为 CurrentView。
如果您希望它永远关闭,还可以提供一个关闭按钮。也就是说,如果您要关闭它,它将从列表中删除并且不会被缓存。
这就像您在窗口中打开了不同的 View 一样,您可以在它们之间切换。如果需要,您可以关闭 View 。
编辑: 见以下代码:
<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
中看到你必须拥有一个属性(property) ZIndex
,它将用于在顶部显示当前 View 。所以每当你想显示 View 时,只需设置 ZIndex
ViewModel
的属性(property)为 1 并将重置 View 重置为 0。
关于c# - 如何使用 DataTemplates 通过 ViewModel-First 方法缓存动态切换的 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30232697/