如果这是相关的;我在我的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的相关重构中有些失败,但是这个错误信息并没有帮助我弄清楚那可能是什么......
有什么建议吗?
答案 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