未显示单例 ViewModel 的视图

View is not shown for singleton ViewModel

我有一个使用 Caliburn.Micro 2.0.1 的 wpf 应用程序,我发现 Caliburn.Micro 有奇怪的行为。最新的3.0.3也有。

重现错误的超级简单项目:https://github.com/ihtfw/CaliburnMicroBug

MainWindowViewModel 是屏幕的导体。 有两个 ScreenViewModel 作为 MainWindowViewModel 的 Items 和 属性 SingletonViewModel。 在 MainViewModel 中,我可以切换到第一个 ScreenViewModel 或第二个。

除了 SingletonViewModel 的视图在切换到第二个屏幕后仅在第二个 ScreenViewModel 上显示外,一切正常。

重现:

如何解决这个问题?

更新

无法使用 ContentControl 制作这些。应该使用显式视图。在这种情况下,SingletonView 并设置它的 DataContext。要连接 Caliburn.Micro 动作,请在没有上下文的情况下绑定它们。所以结果将是:

<local:SingletonView DataContext={Binding Path=SingletonViewModel} cal:Action.TargetWithoutContext="{Binding}" />

我处理过你的项目,发现你的问题出在 MainWindows 构造函数中。像下面这样更改 MainWindow 的构造函数:

public MainWindowViewModel()
    {


        Items.Add(new ScreenViewModel
        {
            DisplayName = "Screen 1",
            SingletonViewModel = new SingletonViewModel()
        });

        Items.Add(new ScreenViewModel
        {
            DisplayName = "Screen 2",
            SingletonViewModel = new SingletonViewModel()
        });

        ActiveItem = Items.First();
    }

这不是 Bug。

一个UIElementUserControl只能有一个逻辑父。

您正在创建两个 ScreenViews,并且您正试图向它们添加相同的 SingletonView,这是不可能的,因为 SingletonView 不能有两个父项。

如其他答案所述,您不能有 "singleton view",xaml UI 模型将不允许相同的 UI 元素出现在可视化树中两次。

但是,您可以将同一视图的两个实例绑定到视图模型。

为此,您需要避开框架的一项功能。

在内部,任何实现 IViewAware 的视图模型都持有对视图的弱引用,每当框架尝试为视图模型定位视图时,它首先查询视图模型以获取该引用。

如果返回引用,则视图将从其现有位置删除并插入到新位置。

为了阻止这种情况,您可以做以下三件事之一:

  1. 不要让您的 SingletonViewModel 继承自实现 IViewAware 的东西,例如 PropertyChangedBase.
  2. 做一些非常 hacky 的事情,并使用下面的第一个代码示例取消附加视图。
  3. 更改 ViewLocator.LocateForModel 以使用下面的第二个代码示例删除此行为。

Hacky 无效视图

protected override void OnViewAttached(object view, object context)
{
    Views[context ?? ViewAware.DefaultContext] = null;
}

删除 IViewAware 行为

ViewLocator.LocatorForModel = (model, location, context) => ViewLocator.LocateForModelType(model.GetType(), location, context);