我使用 UsbHid,示例中的作者在表单类中的视图中创建了所有内容,但我正在尝试将代码传输到 ViewModel
问题出在代码的这些部分:
private void Window_Loaded(object sender, RoutedEventArgs e) {
HwndSource src = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
src.AddHook(new HwndSourceHook(WndProc));
}
和
protected override void OnSourceInitialized(EventArgs e) {
base.OnSourceInitialized(e);
var handle = new WindowInteropHelper(this).Handle;
usb.RegisterHandle(handle);
}
这里this需要表单以便更新 USB 事件,但是如果所有 USB 初始化都发生在DataContext?
namespace MyApp.View {
public partial class MainWindowView:MetroWindow {
public MainWindowView() {
DataContext = new DeveloperModeViewModel();
InitializeComponent();
}
}
}
代码摘自文章
据我了解,目前在您的文章中,窗口用于两个目的:绘制 UI 和接收有关 USB 设备的消息。第一个用法对应 V,第二个用法对应 VM 甚至 M。
这意味着您需要将此功能分离到不同的窗口中。在模型中,您必须在单独的线程中打开一个单独的、不可见的窗口,您将在其中接收必要的 USB 消息。并使用普通窗口进行显示。
现在,要创建一个带有消息循环的不可见功能窗口,可以使用普通的 WPF 窗口
Visible = false(未测试)。但是很有可能,您将需要一个普通的本机窗口,它必须使用 P/Invoke 进行组织。如何做到这一点,最好看这里。从类中删除多余的内容,我们得到以下空白:
类中缺少函数的 P/Invoke 定义
Win32查看相同的http://www.pinvoke.net。在 MVVM 模式下,VM 对象无法知道窗口的任何信息,这超出了它的职责范围。将 Handle 的接收留在窗口类中是正确的。
但已经可以使用 UsbHid 将其取出到 VM 中。顺便问一下,为什么需要两个事件?
只是不要忘记对任何属性的赋值都可能发生多次,这必须正确处理(即,您必须在添加新钩子之前删除旧钩子,等等)。
作为替代方案,您可以使用 MVP 模式。与 ViewModel 不同,Presenter 有权了解视图。因此,Presenter 可以订阅 SourceInitialized 事件。
或者,对于代码重用,尝试使用行为(Behavior)是有意义的: