C# 如何修复';对象引用未设置为对象的实例;使用WPF CR查看器控件时

C# 如何修复';对象引用未设置为对象的实例;使用WPF CR查看器控件时,c#,wpf,crystal-reports,C#,Wpf,Crystal Reports,我正在按照MVVM模式制作一个WPF应用程序 我有一个带有导航控件的窗口,还有一个用于容纳单个用户控件的占位符(contentcontrol)。主窗口的viewmodel维护一个打开的子viewmodels数组,并具有指向数组中单个子viewmodel的“CurrentView”属性。然后将此“CurrentView”属性绑定到主窗口上的contentcontrol占位符。viewmodels都是通过数据模板使用特定视图(用户控件)设置的 当“CurrentView”属性设置为子viewmode

我正在按照MVVM模式制作一个WPF应用程序

我有一个带有导航控件的窗口,还有一个用于容纳单个用户控件的占位符(contentcontrol)。主窗口的viewmodel维护一个打开的子viewmodels数组,并具有指向数组中单个子viewmodel的“CurrentView”属性。然后将此“CurrentView”属性绑定到主窗口上的contentcontrol占位符。viewmodels都是通过数据模板使用特定视图(用户控件)设置的

当“CurrentView”属性设置为子viewmodels之一时,相应的用户控件视图将显示在主窗口的contentcontrol占位符中。一次只显示一个子viewmodel,其余的子viewmodel位于数组中,等待通过设置为CurrentView属性来显示

到目前为止,我对这种模式没有任何问题。它适用于所有标准WPF控件,没有任何问题。我的问题是,只有当我的一个用户控件托管WPF Crystal Report Viewer时

我可以将当前视图设置为具有crystal report Document的viewmodel。我加载报表文档并将其作为公共依赖属性公开。此viewmodel的数据模板用户控件具有WPF Crystal Report Viewer控件。我已将附加属性添加到报表查看器控件,以允许我绑定到.ViewerCore.ReportSource。我将报告文档从viewmodel绑定到附加属性,瞧!所有这些都如预期的那样起作用。我编译我的程序并导航到crystal report viewer。。。它加载绑定报告并正确显示

然而,现在当我离开时(用不同的viewmodel替换主窗口上的“CurrentView”属性),我得到一个错误

起初,我得到的是“属性未设置:窗口”。经过一些搜索,我发现Crystal Report Viewer试图显示一个messagebox,但不知道它的所有者窗口,因此无法显示。为了解决这个问题,我在user controls loaded事件中将crystal report viewer的所有者设置为主窗口。这消除了“属性未设置:窗口”错误

我重新编译,导航到报告,它加载良好。我导航离开,现在我得到一个弹出窗口,上面写着“对象引用未设置为对象的实例”。我点击OK,弹出窗口消失,我的程序继续运行,没有任何可见问题。我可以毫无困难地导航回报告,但每次导航离开时,这个弹出窗口都会显示出来

我无法调试弹出窗口的源代码,因为如果我删除了所有者,它就会被查看器无法找到所有者来显示错误所吞噬


对于冗长的描述,很抱歉。该项目非常大,因此尝试适应源代码将比描述占用更多的空间。如果您想查看我的代码的任何特定部分,请留下评论,我将更新我的问题。

我尝试了一系列不同的断点,并且能够将其缩小到我附加的dep用于绑定到ViewerCore.ReportSource的ndency属性。当我更改为其他视图时,此属性意外设置为null,并且附加的属性没有考虑到这一点。如果将来有人遇到类似问题,您可以使用以下方法:

public static class DependencyPropertyHost
{
    public static readonly DependencyProperty ReportSourceProperty = DependencyProperty.RegisterAttached("ReportSource", typeof(ReportDocument), typeof(DependencyPropertyHost), new PropertyMetadata(ReportSourceChanged));

    public static ReportDocument GetReportSource(DependencyObject obj)
    {
        return obj.GetValue(ReportSourceProperty) as ReportDocument;
    }

    public static void SetReportSource(DependencyObject obj, ReportDocument value)
    {
        obj.SetValue(ReportSourceProperty, value);
    }

    private static void ReportSourceChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        var viewer = sender as CrystalReportsViewer;
        if (viewer != null && args.NewValue != null)
        {
            viewer.ViewerCore.ReportSource = args.NewValue;
        }
    }
}