单例ViewModel

时间:2017-03-10 11:29:44

标签: c# .net wpf caliburn.micro

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

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

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

除了在切换到第二个屏幕后仅在第二个ScreenViewModel上显示View for SingletonViewModel时,一切都很完美。

重现:

  • 启动应用
  • 切换到第二个屏幕
  • 切换回第一个屏幕
  • 未显示SingletonViewModel的视图=(

如何解决这个问题?

更新

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

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

3 个答案:

答案 0 :(得分:3)

如其他答案中所述,您不能拥有“单一视图”,xaml UI模型将不允许相同的UI元素在可视树中两次。

然而,您可以做的是将两个相同视图的实例绑定到视图模型。

要做到这一点,您需要回避框架的一个功能。

在内部,任何实现IViewAware的视图模型都拥有对视图的弱引用,只要框架尝试定位视图模型的视图,它首先会查询该视图的视图模型。

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

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

  1. SingletonViewModel不会继承实施IViewAware的内容,例如PropertyChangedBase
  2. 使用下面的第一个代码示例做一些非常hacky并使附加视图无效。
  3. 使用下面的第二个代码示例更改ViewLocator.LocateForModel以删除此行为。
  4. Hacky null out view

    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);
    

答案 1 :(得分:0)

我参与了您的项目,发现您的问题出在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();
    }

答案 2 :(得分:0)

这不是一个Bug。

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

您正在创建两个ScreenViews,并且您尝试向这两个SingletonView添加相同的SingletonView,这是不可能的,因为class Car < ActiveRecord::Base has_many :prices end class Price < ActiveRecord::Base belongs_to :car end 不能有两个父母。