我们有一个(大规模)遗留WinForms应用程序,通过菜单项打开一个WPF表单。这个WPF表单将托管一个Infragistics网格,以及一些按钮/下拉菜单。
这个单独的WPF表单代表了向WPF迁移的新生阶段。稍后,应用程序的更多组件将转移到WPF,最终转移到整个应用程序本身。
作为迁移的一部分,我们希望使用Caliburn Micro。因此,如果我们可以开始使用这个单独的WPF表单,那就太好了。
我到目前为止阅读的文档涉及引导过滤器,它确保应用程序以所需的根视图模型开始,而不是上面的场景。
非常感谢!
答案 0 :(得分:6)
经过大量Google搜索并浏览Caliburn Micro源代码后,我想出了一种适用于示例测试应用程序的方法。由于某些原因,我不能在这里发布测试应用程序,但简而言之,这就是方法。
在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);
上面的引导程序是你必须写的东西。
它应该在其构造函数中执行以下操作:
// 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"
依赖项属性的值用作字符串传递给Bootstrapper.GetInstance(类型serviceType,字符串键),然后必须使用它来解析WpfControlViewModel。
答案 1 :(得分:2)
跟进接受的答案(好的答案!),我想向您展示如何以ViewModel First方法实现WinForms Bootstrapper,其方式如下:
为此,我们需要创建自己的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
}
}
}
我希望这可以帮助有相同需求的人。它确实救了我。
答案 2 :(得分:1)
以下是您可以从
开始的事情现在,您可以使用视图第一种方法,并使用视图上的Bind.Model附加属性将视图绑定到模型。我创建了一个示例应用程序来描述方法here。