如何使用DataTemplates

时间:2015-05-14 08:28:30

标签: c# wpf xaml mvvm

(我正在使用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)。

我在答案中找到的唯一解决方案是&#34;硬编码&#34; View及其ViewModel(使用DataContext),但遵循此解决方案会发生以下情况:

  • 我打破了ViewModel-First方法。
  • 为了不破坏完整的MVVM,我必须更改CurrentView签名并将其移至我MainWindow.xaml后面的代码。
  • 我没有切换ViewModelBase类型,而是切换具体的控件。

我想知道是否有任何解决方案没有&#34;硬编码&#34;视图模型的视图,所以我可以保持当前的ViewModelBase开关和ViewModel-First方法。

1 个答案:

答案 0 :(得分:5)

您可以采用以下方法:

  1. 而不是ContentControl采取ItemsControl
  2. <ItemsControl ItemsSource="{Binding Views}" SelectedItem="{Binding CurrentView}"/>

    1. ItemsPanel ItemsControl作为网格,SelectedItemZ-Index设置为1,其余项目Z-Index设为MainViewModel 0.通过这种方式,一次只能看到一个视图,而这个视图将会超过其他视图。

    2. Views中选择两个属性。 ObservableCollection<ViewModelBase>类型的CurrentViewViewModelBase类型的ItemsControls,并分别与ItemsSource的{​​{1}}和SelectedItem绑定。

    3. 现在,当您要打开视图时,创建一个ViewModel,将其添加到Views列表并将其设置为CurrentView。如果它已经在列表中,只需将其设置为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,该属性将用于显示顶部的当前视图。因此,只要您想显示视图,只需将ZIndex的{​​{1}}属性设置为1,然后将重置视图重置为0.