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

4

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

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

假设我想处理一些来自WF控件的事件,是否有完全采用MVVM的方法?

谢谢。

3个回答

2
请注意,这并没有真正回答问题(我应该读得更好)。如果您想在WinForms应用程序中使用WPF控件,则可以采用以下方法。我的场景是: 1)有一个WinForms控件,在我的应用程序的许多地方使用。 2)希望开发一个将使用MVVM模式的WPF实现。 3)希望将控件编写为适当的WPF控件,包括依赖属性,以便在我的应用程序最终全部使用WPF时可以正确使用。 4)希望保留相同的WinForms控件和API,以不破坏我的应用程序中现有的客户端代码。
大部分都很直接,除了当我的WPF控件的属性改变时,让我的WinForms控件引发事件。我想使用绑定,但由于绑定的源必须是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();
    }
  }
}

1

就我个人而言,我会创建一个WPF UserControl来包装Windows Forms控件。这将允许您将所有所需的代码封装到您的WPF控件中,并以纯MVVM方式使用它。

如果直接使用Windows Forms控件,则很难保持“纯”MVVM,因为Windows Forms控件通常需要不同的绑定模型,以及通常需要直接事件处理。


那么,如果我有一个封装WinForms控件的WPF用户控件,我可以从WPF用户控件提供WPF绑定,但在内部它将处理WinForms控件?如果是这样,那么这可能正是我想要的方式。 - Stécy
@Stecy:是的-在内部,它将从WPF DependencyProperties映射到设置控件值、接收事件等。然而,从WPF方面来看,这具有与普通WPF控件完全相同的优点。在我看来,这确实是长远来看最好的方法。 - Reed Copsey

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接