WPF Window.Show 引发 InvalidOperationException:窗口必须是树的根.无法将窗口添

本文关键字:窗口 Show Window 引发 InvalidOperationException WPF | 更新日期: 2023-09-27 17:56:13

如果这是相关的;我在我的WPF应用程序中使用Caliburn.Micro和Castle.Windsor。

我有一个带有LoginViewModel的LoginView,它是在应用程序启动时启动的,没有戏剧性。然后,一旦用户登录,从 LoginViewModel 中,我启动一个初始屏幕,主应用程序视图如下所示;

IoC.Get<IWindowManager>().ShowWindow(IoC.Get<SplashScreenViewModel>());
IoC.Get<IWindowManager>().ShowWindow(IoC.Get<MainViewModel>());

第一个调用有效,第二个调用在 Caliburn.Micro 中抛出异常;

Window.Show();

InvalidOperationException消息是:"窗口必须是树的根。无法将窗口添加为视觉对象的子项。

我的理解是 Window.Show() 将窗口放在可视化树的根目录下......此外,或多或少相同的代码在此代码库的先前版本中运行良好,但我在其他领域进行了一些重大重构,现在出现了这种情况。

我猜在我使用 Castle.Windsor Caliburn.Micro 的相关重构中有一些失败,但此错误消息并不能帮助我弄清楚这可能是什么......

有什么建议吗?

WPF Window.Show 引发 InvalidOperationException:窗口必须是树的根.无法将窗口添

我仍然无法确切确定导致此异常的原因,但是我已经通过修改我的(非常广泛的)ViewModel组件注册来解决此问题;

Register(Classes.FromAssembly(GetType().Assembly)
            .Where(x => x.Name.EndsWith("ViewModel"))
            .WithService.Self()
            .WithService.AllInterfaces()
            .Configure(x => x.LifeStyle.Is(LifestyleType.Transient)));

自;

Register(Classes.FromAssembly(GetType().Assembly)
            .Where(x => x.Name.EndsWith("ViewModel"))
            .WithService.Self()
            .WithService.DefaultInterfaces()
            .Configure(x => x.LifeStyle.Is(LifestyleType.Transient)));

似乎使用 AllInterfaces 会产生一个复杂且不必要的依赖树。在这种情况下,通过使用DefaultInterfaces来减少依赖项并没有害处,这已经解决了这个异常,我推测这与某些 View 实例之间的不良循环关系有关。

在我的情况下,"窗口必须是树的根"错误是由于尝试将ListBoxItemsSource绑定到DependencyObjects集合引起的,该集合恰好在索引零处有一个Window实例。

建立集合绑定时,WPF 会检查绑定集合的内容,以确定它是否需要为每个项使用"项容器",以及是否希望集合的内容显示为本机UIElement(没有容器)。我相信这涉及以各种方式测试第一个元素。

这是一个很好的优化WPF如果数据可以直接显示,则不要生成项目容器。但是,如果你确实打算将集合中的项视为数据(即,你的应用是调试辅助工具或反射工具),并且如果数据可以包含Window,则 WPF 的无提示决策会出错,因为如果没有项容器,则无法将Window放在树中。

不仅仅是Window实例在这里可能成为问题。也许更严重的是,如果您计划稍后将集合中的这些UIElement插入到另一个可视化树中,这也会失败,因为 UIElements 不能位于多个可视化树中。

解决方案很简单:只需指定一个ItemTemplate,这将强制 WPF 使用项容器。

<ListBox ItemsSource="{Binding}">
    <ListBox.ItemTemplate>
        <DataTemplate DataType="DependencyObject">
            <TextBlock Text="{Binding}" />
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

[编辑:] 上面的代码可能不足以解决问题。请参阅 https://stackoverflow.com/a/3844808/147511