【问题标题】:Caliburn Micro, How to use ContentControl (or display 'sub' ViewModel) using ViewModel FirstCaliburn Micro,如何首先使用 ViewModel 使用 ContentControl(或显示“子”ViewModel)
【发布时间】:2016-06-01 08:32:50
【问题描述】:

我首先在我的应用程序中使用 MVVM 框架 Caliburn Micro,并使用 ViewModel(或者我是这么认为的)。但是,当我在使用TryClose(true) 无法关闭其父窗口的对话框中遇到问题并偶然发现这个完美概述了我的问题的问题时,我也得到了“TryClose 需要父 IConductor 或带有 Close 方法的视图或IsOpen 属性。”:

Caliburn.Micro - ShowDialog() how to close the dialog?

但是,我不确定如何实施该解决方案。答案是:

移除 cal:Bind.Model 和 cal:View.Model 绑定...

原来使用这些绑定是一种 View-First 方法,我不知道我正在这样做。这是我的冒犯对话的示例:

<UserControl ... Height="206" Width="415">
    <Grid Margin="20">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="AUTO" />
        </Grid.RowDefinitions>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <Button x:Name="Okay" Content="Okay" Width="100" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center" />
            <Button x:Name="Cancel" Content="Cancel" Width="100" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" />
        </Grid>
        <ContentControl cal:View.Model="{Binding TimeSpanViewModel}"/>
    </Grid>
</UserControl>

它只是一个包装器,带有一个用于已经存在的 ViewModel 的 OK 和 cancel 按钮(谁的视图由 caliburn 解决,因此我认为我首先在做 ViewModel)。如果我删除这个cal:View.Model 绑定,我确实恢复了关闭对话框的能力,但我失去了所有实际内容。我正在使用 ContentControl 来显示整个应用程序中的内容(在 ItemsControls、对话框、弹出窗口等中)。

我的问题是,应该如何首先在 Caliburn 中显示 ViewModel?

编辑:我正在使用 WindowManager 显示 DialogViewModel(继承屏幕),如下所示:

[Export(typeof(IWindowManager))]
public class AppWindowManager : MetroWindowManager, IDialogManager
{
    AppViewModel Content { get; set; }

    public AppWindowManager()
    {

    }

    public override MetroWindow CreateCustomWindow(object view, bool windowIsView)
    {
        if (windowIsView)
        {
            return view as MainWindowContainer;
        }

        MainWindowContainer window = new MainWindowContainer();
        //{
        window.Content = view;
        //};

        return window;
    }

    public override bool? ShowDialog(object rootModel, object context = null, IDictionary<string, object> settings = null)
    {
        Window window = CreateWindow(rootModel, true, context, settings);

        return window.ShowDialog();
    }

    public object ShowCustomDialog(object rootModel, string title, bool showWindowsOptions = true)
    {
        dynamic settings = new ExpandoObject();
        settings.Title = title;
        settings.ShowCloseButton = showWindowsOptions;
        settings.ShowMaxRestoreButton = showWindowsOptions;
        settings.ShowMinButton = showWindowsOptions;
        settings.SizeToContent = SizeToContent.WidthAndHeight;
        return ShowDialog(rootModel, null, settings);
    }

    public ILoadingDialogViewModel CreateLoadingDialogManager()
    {
        return new LoadingDialogViewModel(this);
    }
}

【问题讨论】:

  • 或许您应该添加更多详细信息:您是否使用conductor 来显示您的对话框? TryClose 有什么问题?您是否看到另一个问题的相同信息?
  • 这是视图模型,因为您没有使用用户控件来指定视图,而是基于视图模型将视图加载到内容控件中。如果您提供要绑定/创建视图模型到/用于的用户控件,则只有视图优先。您的子视图模型是否有 candeactivate 挂钩?
  • 子 (TimeSpanViewModel) 继承 PropertyChangedBase 并且托管它的对话框 ViewModel(查看上面的代码)实现 Screen。我没有接触过 caliburn 中的停用钩子。
  • @IlVic 我从 caliburn 收到相同的日志消息:“TryClose 需要父 IConductor 或具有 Close 方法或 IsOpen 属性的视图。”我没有显示带有导体的 ViewModel,而是在使用 WindowManager 的窗口中显示(如果有任何帮助,我已将该代码添加到问题中)

标签: c# wpf mvvm caliburn.micro


【解决方案1】:

回答主要问题

我应该如何在 ViewModel 第一个 Caliburn 中显示 ViewModel?

我假设 TimeSpanViewModel 是您在 ViewModel 上拥有的一个属性,它有一个 [Import] (并且 ViewModel 正在导出自己)?我认为您应该将cal:View.Model="{Binding TimeSpanViewModel}" 更改为x:Name="TimeSpanViewModel"。即使这可能无法解决问题,但这是正确的做法,Caliburn 会确保它被正确绑定。

我试图重现您的问题,但即使使用您的方式它也对我有用。那么为什么它不能按照您目前的方式工作,这是一个很好的(第二个)问题。

最大的问题可能是您的 AppWindowManager,如果您在其中创建的窗口没有通过正确的 Caliburn 代码,它将无法正确绑定。由于缺少很多代码,我什至不确定AppViewModel Content { get; set; } 在那里做什么,主要是我只能推测。您是否尝试使用默认的 WindowManager 实现,只是为了看看它是否适用?

【讨论】:

  • 我认为窗口管理器的问题可能是正确的,我将尝试使用默认实现。我试过 x:Name="TimeSpanViewModel" 并得到相同的结果。 TimeSpanViewModel 确实是 DialogViewModel 上的一个属性。我不确定您所说的 [导入] 是什么意思。我有 ViewModel 和 View 文件(如果我将 View 文件命名错误,Caliburn 无法连接它并报告“找不到 TimeSeriesViewModel 的视图”)
  • TimeSpaceViewModel 必须来自某个地方,这就是我对导入的意思...(您的窗口管理器上有导出,所以我假设您使用 MEF)。
  • 我正在开发一个项目,希望它易于使用:翻译、配置、Caliburn.Micro、MahApps、NotifyIcon WPF 和 MEF。这可以在这里找到:github.com/dapplo/Dapplo.CaliburnMicro 并且有一个演示项目,我在其中添加了一个对话框。
  • “CredentialsViewModel”对话框位于设置右上角的登录按钮后面,它可以毫无问题地打开和关闭。该演示可能看起来很糟糕,但它只是一个演示,展示了使用这些功能是多么“容易”(记住您的语言设置),此外它还在进行中......这些项目是为新版本的 Greenshot 编写的。跨度>
  • 我没有使用 MEF(但是!我可能会,所以这是一个非常有趣的项目)。该 Import 可能来自我从中获取 AppWindowManager(来自 Caliburn.Metro)实现的项目。我将项目重新配置为使用标准的 WindowManager 和标准的 ShowDialog,但仍然有相同的错误。奇怪的是,我所有的其他对话框都可以正常工作,如果我删除 ContentControl,对话框功能正常。我会看看你的实现。
【解决方案2】:

对于那些刚接触 Caliburn.Micro 并与此线程相关的人,如果您在 AppBootStrapper 中使用 Caliburn.Micro 的 SimpleContainer 作为 IoC 依赖注入容器,则不要使用 MEF 或任何其他 IoC 容器实现。

互联网上流传的很多旧 StackOverflow 讨论和代码都使用 MEF 和 Caliburn.Micro,但 Caliburn.Micro 提供的 SimpleContainer 可能足以满足您的项目(如果是这样,请不要让 MEF 代码混淆您何时看例子)。

Calburn.Micro Wiki entry for SimpleContainer.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-26
    • 2020-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-15
    • 2018-03-15
    • 2013-12-30
    相关资源
    最近更新 更多