【问题标题】:View is not shown for singleton ViewModel未显示单例 ViewModel 的视图
【发布时间】:2017-03-10 11:29:44
【问题描述】:

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

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

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

除了 SingletonViewModel 的视图在切换到第二个屏幕后仅在第二个 ScreenViewModel 上显示之外,一切都完美无缺。

复制:

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

如何解决这个问题?

更新

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

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

【问题讨论】:

    标签: c# .net wpf caliburn.micro


    【解决方案1】:

    正如其他答案中所述,您不能拥有“单一视图”,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);
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 是的,它会工作,但 SingletonViewModel 应该是单例的!而在你改变之后就不是了。
      【解决方案3】:

      这不是错误。

      UIElement(例如 UserControl)只能有一个逻辑父级。

      您正在创建两个ScreenViews,并尝试将相同的SingletonView 添加到它们,这是不可能的,因为SingletonView 不能有两个父母。

      【讨论】:

      • 每个 ScreenView 都有自己的 SigletonView,而 SingletonViewModel 只是 DataContext。为什么 Caliburn.Micro 不可能做到这一点?如果我写了 没关系。但是 行不通
      • 每个屏幕都是...但是您有一个承载 SingletonView 的 ContentControl,并且您只创建该视图的一个实例,根本不可能。如果您希望 ViewModel 的单个实例成为两个 View 的 DataContext,那么您必须使用另一种方法。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多