使用WPF, MVVM和绑定与WinForm UserControl,如何成功集成



我在WPF窗口中有一个WinForm UserControl, WPF代码使用MVVM模式。

将WinForm控件成功集成到MVVM模式中的最佳方法是什么?我可以从WPF端使用某种形式的绑定吗?

假设我想处理WF控件中的一些事件,是否有一种方法可以完全使用MVVM?

谢谢。

请注意,这并没有真正回答问题(我应该读得更好)。如果你对在WinForms应用程序中使用WPF控件感兴趣,这里有一个方法。我的设想是:1)有一个WinForms控件,在我的应用程序中使用了很多地方。2)想开发一个使用MVVM模式的WPF实现。3)想把控件写为一个适当的WPF控件完成依赖属性,这样当我的应用程序最终都是WPF时,它可以被正确使用。4)想要保持相同的WinForms控件和API,以不破坏现有的客户端代码在我的应用程序。

除了让我的WinForms控件在我的WPF控件的属性改变时引发事件外,大多数事情都很简单。我想使用绑定,但因为绑定的源必须是一个DependencyObject,而System.Windows.Forms.UserControl不是,所以我不得不做一个简单的嵌套类。我写我的WPF控件,就好像我要把它集成到一个WPF应用程序,只是做了一些额外的思考,让我的WinForms包装工作。

下面是我的WPF控件的代码:
public partial class MonkeySelector : UserControl
{
  public static readonly DependencyProperty SelectedMonkeyProperty =
    DependencyProperty.Register(
    "SelectedMonkey", typeof(IMonkey),
    typeof(MonkeySelector));
  public MonkeySelector()
  {
    InitializeComponent();
  }
  protected override void OnInitialized(EventArgs e)
  {
    base.OnInitialized(e);
    // Note: No code is shown for binding the SelectedMonkey dependency property
    // with the ViewModel's SelectedMonkey property. This is done by creating
    // a Binding object with a source of ViewModel (Path = SelectedMonkey) and
    // target of the SelectedMonkey dependency property. In my case, my
    // ViewModel was a resource declared in XAML and accessed using the
    // FindResource method.
  }
  public IMonkey SelectedMonkey
  {
    get { return (IMonkey)GetValue(SelectedMonkeyProperty); }
    set { SetValue(SelectedMonkeyProperty, value); }
  }
}

下面是我的WinForms控件的代码:

public partial class WinFormsMonkeySelector : UserControl
{
  public event EventHandler SelectedMonkeyChanged;
  private MonkeySelector _monkeySelector;
  private WpfThunker _thunker;
  public WinFormsMonkeySelector()
  {
    InitializeComponent();
    _monkeySelector = new MonkeySelector();
    _elementHost.Child = _monkeySelector;
    System.Windows.Data.Binding binding = new System.Windows.Data.Binding("SelectedMonkey");
    binding.Source = _monkeySelector;
    binding.Mode = System.Windows.Data.BindingMode.OneWay;
    _thunker = new WpfThunker(this);
    // Note: The second parameter here is arbitray since we do not actually
    // use it in the thunker. It cannot be null though. We could declare
    // a DP in the thunker and bind to that, but that isn't buying us anything.
    System.Windows.Data.BindingOperations.SetBinding(
      _thunker,
      MonkeySelector.SelectedMonkeyProperty,
      binding);
  }
  protected virtual void OnSelectedMonkeyChanged()
  {
    if (SelectedMonkeyChanged != null)
      SelectedMonkeyChanged(this, EventArgs.Empty);
  }
  public IMonkey SelectedMonkey
  {
    get { return _monkeySelector.SelectedMonkey; }
    set { _monkeySelector.SelectedMonkey = value; }
  }
  private class WpfThunker : System.Windows.DependencyObject
  {
    private WinFormsMonkeySelector _parent;
    public WpfThunker(WinFormsMonkeySelector parent)
    {
      _parent = parent;
    }
    protected override void OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs e)
    {
      base.OnPropertyChanged(e);
      // Only need to check the property here if we are binding to multiple
      // properties.
      if (e.Property == MonkeySelector.SelectedMonkeyProperty)
        _parent.OnSelectedMonkeyChanged();
    }
  }
}

就我个人而言,我会通过创建一个WPF UserControl来包装Windows窗体控件来处理这个问题。这将允许您将所有所需的代码封装到WPF控件中,然后以纯MVVM的方式使用它。

直接使用Windows窗体控件将很难保持"纯"MVVM,因为Windows窗体控件通常需要不同的绑定模型,以及通常需要直接的事件处理。

您可以看一下WAF Windows Forms Adapter。它展示了一种将Windows窗体与MVVM一起使用的可能方法。

相关内容

最新更新