2015-05-14 40 views
2

(我用GalaSoft.MvvmLight框架)如何动态高速缓存使用的DataTemplates

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

使用以下技术与它们的对应视图模型结合这些观点以下技术之间切换上述E观点:

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

我已经找到我的答案,唯一的解决办法是“硬编码”,其视图模型视图(使用的DataContext),但是遵循这个解决方案波纹管发生了:

  • 我打破视图模型优先方法。
  • 为了不中断完整的MVVM,我必须更改CurrentView签名并将其移至我的MainWindow.xaml后面的代码。
  • 而不是切换ViewModelBase类型,我切换具体控件。

我想知道是否有没有“硬编码的”与视图模型视图的任何解决方案,这样我就可以保持当前ViewModelBase开关和视图模型优先的方法。

回答

4

可以有以下方法:

  1. 而不是采取ContentControl采取ItemsControl

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

  • 采取ItemsControlItemsPanel如一个Grid并为SelectedItem设置Z-Index为1并为其余项目s将Z-Index设置为0.以这种方式,只有一个视图在其他视图上可见。

  • MainViewModel中取两个属性。 Views类型ObservableCollection<ViewModelBase>CurrentView类型ViewModelBase并分别与ItemsControlsItemsSourceSelectedItem绑定。

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

    如果您希望它永久关闭,还可以提供关闭按钮。即如果您关闭它,它将从列表中移除并且不会被缓存。

    这会像在窗口中打开不同视图一样工作,您可以在它们之间切换。如果你想要,你可以关闭一个视图。

    编辑: 请参见下面的代码:

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

    +0

    感谢您的回答,似乎没有'ItemsControl'的SelectedItem属性。该属性仅适用于'Selector'派生类。如果我理解你的答案是正确的,你的意思是一个“TabControl”?一个示例代码将非常感谢。 – Eido95

    +1

    对不起,我感到困惑。是的你是对的,'ItemsControl'没有'SelectedItem'属性。我已经更新了我的答案并提供了'xaml'参考。是的,您可以说它与“TabControl”类似,但不是全部。在这里你可以提供更多的功能。我在我的一个项目中使用了相同的结构。 –

    +0

    谢谢你提供代码给你的答案,它更容易理解。我完全写了你提供的代码,并在'ViewModelBase'内部实现'ZIndex'属性,以便在ViewModels之间共享。这是完美的工作!非常感谢您的回答! – Eido95