我有一個WPF窗口內的WinForm UserControl和WPF代碼使用MVVM模式。使用WPF,MVVM和綁定與WinForm UserControl,如何成功集成?
將WinForm控件成功集成到MVVM模式的最佳方法是什麼? 我可以使用WPF方面的某種形式的綁定嗎?
假設我想處理來自WF控件的一些事件,是否有辦法完全使用MVVM?
謝謝。
我有一個WPF窗口內的WinForm UserControl和WPF代碼使用MVVM模式。使用WPF,MVVM和綁定與WinForm UserControl,如何成功集成?
將WinForm控件成功集成到MVVM模式的最佳方法是什麼? 我可以使用WPF方面的某種形式的綁定嗎?
假設我想處理來自WF控件的一些事件,是否有辦法完全使用MVVM?
謝謝。
個人而言,我會通過創建一個包裝Windows窗體控件的WPF UserControl來處理此問題。這將允許您將所有必需的代碼隱藏到您的WPF控件中,然後以純MVVM方式使用它。
由於Windows窗體控件通常需要不同的綁定模型,並且通常需要直接事件處理,所以直接使用Windows窗體控件很難保持「純粹」MVVM。
你可能會看看WAF Windows Forms Adapter。它顯示了將Windows Forms與MVVM一起使用的一種可能方式。
請注意,這並不真正回答問題(我應該讀得更好)。如果您有興趣在WinForms應用程序中使用WPF控件,請使用下面的方法。我的方案是: 1)有一個WinForms控件在我的應用程序中使用很多地方。 2)要開發一個WPF實現,它將使用MVVM模式。 3)想要將控件編寫爲具有依賴屬性的完整WPF控件,以便在我的應用程序最終都是WPF時正確使用它。 4)想要保持相同的WinForms控件和API不會破壞我的應用程序中的現有客戶端代碼。
除了讓我的WinForms控件在我的WPF控件的屬性更改時引發事件以外,大多數情況都很簡單。我想使用綁定,但由於綁定的來源必須是DependencyObject,而System.Windows.Forms.UserControl不是,我必須製作一個簡單的嵌套類。我寫了我的WPF控件,就好像我將它集成到WPF應用程序中一樣,只是做了一些額外的thunking讓我的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用戶控件封裝的WinForms控制,我可以提供WPF從WPF用戶控件綁定但內部它會處理WinForms控件?如果是這樣,那麼它可能就是我想要的方式。 – 2011-04-07 18:51:49
@Stecy:是的 - 在內部,它將最終完成從WPF DependencyProperties到設置控件值,接收事件等的映射。但是,從WPF方面來看,這看起來好像正常的WPF控件。從長遠來看,IMO確實是最好的方式。 – 2011-04-07 18:55:17