2012-01-31 120 views
4

我们有一个(大规模)传统的WinForms应用程序,它通过菜单项打开一个WPF表单。这个WPF表单将托管一个Infragistics网格,以及一些按钮/下拉菜单。如何在WinForms应用程序中使用Caliburn Micro和一个WPF表单

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

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

  • 有人可以请提供一些关于如何使用Caliburn Micro与WPF窗体?
  • 或者告诉我为什么使用Caliburn Micro可能没有意义?

我到目前为止阅读过的文档涉及到确保应用程序以期望的根视图模型启动而不是上述情景的启动打包程序。

非常感谢!

+0

我认为,在这种情况下,C.M.会比解决更麻烦。厘米。旨在帮助纯WPF应用程序通过其广泛/自动化的MVVM框架更快地“启动并运行”。你的应用程序已经过去了从框架构建阶段,在这个阶段引入新应用程序将是非常具有挑战性的。 最可能帮助你的是应用坚实的MVVM(艰难的方式),转换到WPF。由于该项目在WinForms中,因此它有一个非零机会,因为它是用一个体面的MVC implimentation构建的,所以向MVVM的这种转换可能不那么痛苦。祝你好运! – EtherDragon 2012-02-01 00:23:45

回答

5

经过大量的谷歌搜索和Caliburn微源代码,我想出了一个可以在样本测试应用程序中工作的方法。由于某些原因,我无法在此处发布测试应用程序,但这里简单介绍一下。

  • 用按钮创建一个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); 
    
  • 上面的引导程序是你得写。

  • 有关它需要做的所有事情的更多信息,请参阅 documentation中的Customizing the Bootstrapper
  • 对于本文的目的,使它来自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; 
    } 
    
  • 最后一点要注意的是,你必须设置CAL:绑定。WpfControlView的XAML中的模型依赖项属性。

    
    cal:Bind.Model="WpfControls.ViewModels.WpfControl1ViewModel" 
    
  • 依赖性属性的值被用作字符串Bootstrapper.GetInstance(类型的serviceType,串键),则必须用它来解决WpfControlViewModel通过。

  • 由于我使用的容器(Autofac)不支持字符串解析,所以我选择将属性设置为视图模型的完全限定名称。然后可以将此名称转换为类型,并用于从容器中解析。
+0

你可以使用ViewModelBinder.Bind(rootViewModel,rootView,null);在ViewLocator.LocateForModel之后,而不是cal:Bind.Model – Anders 2014-01-28 14:40:05

1

这里有出头就可以开始与

  • 创建的ViewModels和由CM框架提供PropertyChangedBase类继承他们。
  • 如果需要,使用EventAggregator建立松散耦合通信\集成
  • 实现AppBootStrapper,而不使用定义根视图模型的通用实现。

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

2

跟进接受的答案,我想向您展示如何实现的WinForms引导程序的视图模型优先的方法,在某种程度上(好的!):

  1. 你赢了不必创建一个WPF窗口,并且您不必直接绑定到View中的ViewModel。

为此,我们需要建立我们自己的窗口管理器的版本,确保我们不呼吁窗口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     
     } 
    } 
} 

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

相关问题