DataTemplate驱动的视图注入MVVM

时间:2009-09-25 17:19:10

标签: wpf mvvm memory-management datatemplate instantiation

我有一个类似于

的容器视图
<UserControl x:Class="Views.ContainerView">
    <UserControl.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:Type viewmodels:AViewModel}">
                <views:MyView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewmodels:BViewModel}">
                <views:MyView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewmodels:CViewModel}">
                <views:MyView />
            </DataTemplate>
            <DataTemplate DataType="{x:Type viewmodels:DViewModel}">
                <views:MyView />
            </DataTemplate>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid>
        <ListBox ItemsSource="{Binding Path=AvailableViewModels}" 
            SelectedItem="{Binding Path=CurrentViewModel}" 
            IsSynchronizedWithCurrentItem="True" />
        <ContentControl Content="{Binding Path=CurrentViewModel}" />
    </Grid>
</UserControl>

我的所有视图模型都继承了BaseViewModel,因此我将视图转换为此

<UserControl x:Class="Views.ContainerView">
    <UserControl.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:Type viewmodels:BaseViewModel}">
                <views:MyView />
            </DataTemplate>
        </ResourceDictionary>
    </UserControl.Resources>
    <StackPanel>
        <ListBox ItemsSource="{Binding Path=AvailableViewModels}" 
            SelectedItem="{Binding Path=CurrentViewModel}" 
            IsSynchronizedWithCurrentItem="True" />
        <ContentControl Content="{Binding Path=CurrentViewModel}" />
    </StackPanel>
</UserControl>

认为它只会实例化一个MyView,并在ListBox.SelectedItem更改时重新绑定viewmodel。我是否正确理解了这种行为?这是首选做法吗?当我在视图之间切换时,如何验证我没有搅动内存?

2 个答案:

答案 0 :(得分:2)

要扩展Pavel的答案并阐明在更改视图模型时视图会发生什么,将为新视图模型生成新视图,旧视图将希望成为垃圾及时收集。

有问题的是,有时我们会在后面的代码中注册一些事件(非弱事件),这会阻止视图被收集,而内存泄漏。

两种方法。

  1. 视图代码隐藏中的任何事件订阅都应该削弱(PRISM中的EventAggregator)以允许垃圾回收。
  2. 使用unity容器注册视图实例,并在需要重用它时解决它。在将其注入区域之前,只需更新DataContext。
  3. 希望这有帮助。

答案 1 :(得分:1)

它将为您使用的每个视图模型实例化一个新的MyView。如果要重用用户控件,可以在每个用户控件上设置DataContext属性。