【问题标题】:ContentPresenter and Datatemplates with dependency properties具有依赖属性的 ContentPresenter 和 Datatemplates
【发布时间】:2013-11-05 15:44:03
【问题描述】:

主应用程序窗口,减去大量不相关的代码。

<Window>
    <Window.Resources>
    <DataTemplate DataType="{x:Type presenters:DashboardViewModel}">
        <views:DashboardView />
    </DataTemplate>
    <DataTemplate DataType="{x:Type presenters:SecondViewModel}">
        <views:SecondView />
    </DataTemplate>
    </Window.Resources>

    <ContentPresenter Content="{Binding WindowPresenter}"/>
</Window>

绑定到Window的视图模型

public class RootViewModel {
    // IRL this implements notifypropchanged
    public IPresenter WindowPresenter {get; set;}
    public void ShowDashboard(){ this.WindowPresenter = new DashBoardViewModel(); }
    public void ShowSecond(){ this.WindowPresenter = new SecondViewModel(); }
}

DashboardViewSecondView 是具有许多依赖属性的用户控件,这些属性绑定到各自视图模型中的属性。

// example of a common dependency property I have 
public static readonly DependencyProperty ColorPaletteProperty = DependencyProperty.Register("ColorPalette", typeof(ColorPalette), typeof(SurfaceMapControl), new PropertyMetadata(ColorPalette.Rainbow, new PropertyChangedCallback(SurfaceMapControl.ColorPalettePropertyChanged)));
private static void ColorPalettePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((SurfaceMapControl)d).OnColorRangeChanged(); }
private void OnColorRangeChanged() { 
    // code that uses this.SomeOtherDependencyProperty
    // throws null ref exception
}

调用ShowDashboard() 时,内容呈现器会显示正确的用户控件并且所有属性都正确绑定。 在调用ShowSecond() 时,内容呈现器显示正确的用户控件并且所有属性都正确绑定。

有时在两个视图之间切换时,我会在其中一个用户控件的依赖项属性中出现空引用异常,因为我的某些属性会查看其他依赖项属性。这让我相信 viewmodel 在 vi​​ew 之前就被垃圾回收了,viewmodel 的变化会触发 usercontrols 依赖属性,这反过来又会抛出异常,因为 viewmodel 不再存在。

我可以防止在视图模型被释放时触发依赖属性吗?

或者是否有必要在每个依赖属性中进行空数据上下文检查?

我应该在此处添加一些内容来查看用户控件的生命周期以完全防止这种情况发生吗?

【问题讨论】:

  • 空引用来自什么地方? DP的属性改变事件?
  • 如上代码中所说this.SomeOtherDependencyProperty为null。

标签: c# wpf mvvm


【解决方案1】:

WPF 在绑定时,通常对它的所有绑定操作使用弱引用,以防止发生内存泄漏。

因此,您的 ViewModel 可能会在某个时候被清理并消失,而控件仍然“活动”,因为 ViewModel 上的 GC 可能在视图实际关闭之前发生。

最简单的解决方案通常是通过空检查处理这些更改通知,并跳过代码的适当部分。这也很有用,具体取决于您在初始化/创建时的设置方式。

【讨论】:

    猜你喜欢
    • 2011-04-21
    • 2021-12-04
    • 1970-01-01
    • 1970-01-01
    • 2012-04-16
    • 2011-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多