如何在具有一个WPF格式的WinForms应用程序中使用Caliburn Micro

问题描述 投票:4回答:3

我们有一个(大规模)遗留WinForms应用程序,它通过菜单项打开一个WPF表单。这个WPF表单将托管一个Infragistics网格,以及一些按钮/下拉菜单。

这个单独的WPF表单代表了向WPF迁移的新生阶段。稍后,应用程序的更多组件将转移到WPF,最终转移到整个应用程序本身。

作为迁移的一部分,我们希望使用Caliburn Micro。因此,如果我们可以从这个单独的WPF表单开始使用它会很好。

  • 有人可以提供一些关于如何使用Caliburn Micro和WPF表格的指示吗?
  • 或者也许告诉我为什么使用Caliburn Micro可能没有意义呢?

到目前为止我读过的文档涉及引导过滤器,它确保应用程序以所需的根视图模型开始,而不是上面的场景。

非常感谢!

wpf caliburn.micro
3个回答
6
投票

经过大量谷歌搜索并通过Caliburn Micro源代码,我想出了一种适用于样本测试应用程序的方法。由于某些原因,我不能在这里发布测试应用程序,但简而言之,这就是方法。

  • 使用按钮创建WinForm。
  • 单击按钮,显示ChildWinForm
  • 在ChildWinForm的加载处理程序中: // You'll need to reference WindowsFormsIntegration for the ElementHost class // ElementHost acts as the "intermediary" between WinForms and WPF once its Child // property is set to the WPF control. This is done in the Bootstrapper below. var elementHost = new ElementHost{Dock = DockStyle.Fill}; Controls.Add(elementHost); new WpfControlViewBootstrapper(elementHost);
  • 上面的引导程序是你必须写的东西。
  • 有关它需要做的所有信息的更多信息,请参阅Customizing the Bootstrapper Caliburn Micro中的documentation
  • 出于本文的目的,使其派生自Caliburn Bootstrapper类。
  • 它应该在其构造函数中执行以下操作: // Since this is a WinForms app with some WPF controls, there is no Application. // Supplying false in the base prevents Caliburn Micro from looking // for the Application and hooking up to Application.Startup protected WinFormsBootstrapper(ElementHost elementHost) : base(false) { // container is your preferred DI container var rootViewModel = container.Resolve(); // ViewLocator is a Caliburn class for mapping views to view models var rootView = ViewLocator.LocateForModel(rootViewModel, null, null); // Set elementHost child as mentioned earlier elementHost.Child = rootView; }
  • 最后要注意的是,您必须在WpfControlView的XAML中设置cal:Bind.Model依赖项属性。 cal:Bind.Model="WpfControls.ViewModels.WpfControl1ViewModel"
  • dependency属性的值用作字符串传递给Bootstrapper.GetInstance(类型serviceType,string key),然后必须使用它来解析WpfControlViewModel。
  • 由于我使用的容器(Autofac)不支持仅字符串解析,因此我选择将该属性设置为视图模型的完全限定名称。然后可以将此名称转换为该类型,并用于从容器中解析。

2
投票

继续接受已接受的答案(好的!),我想向您展示如何在ViewModel First方法中实现WinForms Bootstrapper,方式如下:

  1. 您不必创建WPF窗口,
  2. 您不必从View中直接绑定到ViewModel。

为此,我们需要创建自己的WindowManager版本,确保我们不在Window上调用Show方法(如果适用于您的情况),并允许绑定发生。

这是完整的代码:

public class WinformsCaliburnBootstrapper<TViewModel> : BootstrapperBase where TViewModel : class
{

    private UserControl rootView;

    public WinformsCaliburnBootstrapper(ElementHost host)
        : base(false)
    {
        this.rootView = new UserControl();
        rootView.Loaded += rootView_Loaded;
        host.Child = this.rootView;
        Start();
    }

    void rootView_Loaded(object sender, RoutedEventArgs e)
    {
        DisplayRootViewFor<TViewModel>();
    }

    protected override object GetInstance(Type service, string key)
    {
        if (service == typeof(IWindowManager))
        {
            service = typeof(UserControlWindowManager<TViewModel>);
            return new UserControlWindowManager<TViewModel>(rootView);
        }
        return Activator.CreateInstance(service);
    }

    private class UserControlWindowManager<TViewModel> : WindowManager where TViewModel : class
    {
        UserControl rootView;

        public UserControlWindowManager(UserControl rootView)
        {
            this.rootView = rootView;
        }

        protected override Window CreateWindow(object rootModel, bool isDialog, object context, IDictionary<string, object> settings)
        {
            if (isDialog) //allow normal behavior for dialog windows.
                return base.CreateWindow(rootModel, isDialog, context, settings);

            rootView.Content = ViewLocator.LocateForModel(rootModel, null, context);
            rootView.SetValue(View.IsGeneratedProperty, true);
            ViewModelBinder.Bind(rootModel, rootView, context);
            return null;
        }

        public override void ShowWindow(object rootModel, object context = null, IDictionary<string, object> settings = null)
        {              
            CreateWindow(rootModel, false, context, settings); //.Show(); omitted on purpose                
        }
    }
}

我希望这可以帮助有相同需求的人。它确实救了我。


1
投票

以下是您可以开始的事情

  • 创建ViewModel并从CM框架提供的PropertyChangedBase类继承它们。
  • 如果需要,请使用Event Aggregator实现进行松散耦合的通信\集成
  • 实现AppBootStrapper而不使用定义根视图模型的通用实现。

现在,您可以使用视图第一种方法,并使用视图上的Bind.Model附加属性将视图绑定到模型。我已经创建了一个示例应用程序来描述here的方法。

© www.soinside.com 2019 - 2024. All rights reserved.