WPF Window.Show抛出InvalidOperationException:Window必须是树的根。无法将Window添加为Visual的子级

时间:2014-04-03 00:26:10

标签: c# wpf castle-windsor caliburn.micro

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

我有一个带有LoginViewModel的LoginView,它在没有戏剧的应用程序启动时启动。然后,一旦用户登录,从LoginViewModel中,我启动SplashScreen,并启动主应用程序视图;

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

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

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

Window.Show();

InvalidOperationException消息是:&#34;窗口必须是树的根。无法将Window添加为Visual的孩子。&#34;

我的理解是Window.Show()窗口放在Visual Tree的根目录中...而且,或多或少这个相同的代码在此代码库的先前版本中正常工作,但我在其他领域做了一些重大的重构,现在已经出现了这个问题。

我猜测在我使用Castle.Windsor或Caliburn.Micro的相关重构中有些失败,但是这个错误信息并没有帮助我弄清楚那可能是什么......

有什么建议吗?

2 个答案:

答案 0 :(得分:0)

我仍无法准确确定导致此异常的原因,但我已通过修改我的(非常广泛的)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实例之间的循环关系错误有关。

答案 1 :(得分:0)

在我的情况下,“窗口必须是树的根”错误是由于尝试将ListBox的{​​{1}}绑定到DependencyObjects的集合而引起的碰巧在索引零处有一个Window实例。

在建立集合绑定时,WPF会检查绑定集合的内容,以确定是否需要为每个项目使用“项目容器” - 而不是您是否打算将集合的内容显示为本机{ {1}} s(没有容器)。我认为这涉及以各种方式测试第一个元素。

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

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

解决方案很简单:只需指定UIElement即可强制WPF使用项容器。

ItemTemplate

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