RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 630375
Accepted
Fangog
Fangog
Asked:2020-02-20 21:43:38 +0000 UTC2020-02-20 21:43:38 +0000 UTC 2020-02-20 21:43:38 +0000 UTC

如何正确地将窗口从V拖到VM?

  • 772

我使用 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();
        }

    }
}

代码摘自文章

c#
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. Best Answer
    VladD
    2020-02-20T22:03:56Z2020-02-20T22:03:56Z

    据我了解,目前在您的文章中,窗口用于两个目的:绘制 UI 和接收有关 USB 设备的消息。第一个用法对应 V,第二个用法对应 VM 甚至 M。

    这意味着您需要将此功能分离到不同的窗口中。在模型中,您必须在单独的线程中打开一个单独的、不可见的窗口,您将在其中接收必要的 USB 消息。并使用普通窗口进行显示。

    现在,要创建一个带有消息循环的不可见功能窗口,可以使用普通的 WPF 窗口Visible = false(未测试)。但是很有可能,您将需要一个普通的本机窗口,它必须使用 P/Invoke 进行组织。如何做到这一点,最好看这里。

    从类中删除多余的内容,我们得到以下空白:

    IntPtr hInstance = Process.GetCurrentProcess().Handle;
    WNDCLASS wndclass;
    
    wndclass.lpfnWndProc = (WndProc)((hWnd, message, wParam, lParam) => {
        IntPtr hdc;
        PAINTSTRUCT ps;
        RECT rect;
    
        usb.ParseMessages(...);
    
        switch ((WM)message)
        {
            case WM.DESTROY:
                Win32.PostQuitMessage(0);
                return IntPtr.Zero;
        }
    
        return Win32.DefWindowProc(hWnd, (WM)message, wParam, lParam);
    });
    
    wndclass.hInstance = hInstance;
    wndclass.lpszClassName = "USBHelper";
    
    ushort regResult = Win32.RegisterClass(ref wndclass);
    
    if (regResult == 0)
        throw new InvalidOperationExcetoon("Shouldn't happen");
    
    IntPtr hwnd = Win32.CreateWindowEx(
        WindowStylesEx.WS_EX_OVERLAPPEDWINDOW,
        new IntPtr((int)(uint)regResult),
        "", // window caption
        WindowStyles.WS_OVERLAPPEDWINDOW, // window style
        Win32.CW_USEDEFAULT, // initial x position
        Win32.CW_USEDEFAULT, // initial y position
        Win32.CW_USEDEFAULT, // initial x size
        Win32.CW_USEDEFAULT, // initial y size
        IntPtr.Zero, // parent window handle
        IntPtr.Zero, // window menu handle
        hInstance, // program instance handle
        IntPtr.Zero); // creation parameters
    
    if (hwnd == IntPtr.Zero)
    {
        int lastError = Marshal.GetLastWin32Error();
        throw new Win32Exception(lastError);
    }
    
    // ShowWindow не нужен, чтобы окно не показывалось
    // Win32.ShowWindow(hwnd, ShowWindowCommands.Normal);
    // Win32.UpdateWindow(hwnd);
    
    // цикл сообщений
    MSG msg;
    while (Win32.GetMessage(out msg, IntPtr.Zero, 0, 0) != 0)
    {
        Win32.TranslateMessage(ref msg);
        Win32.DispatchMessage(ref msg);
    }
    

    类中缺少函数的 P/Invoke 定义Win32查看相同的http://www.pinvoke.net。

    • 1
  2. Pavel Mayorov
    2020-02-20T22:43:37Z2020-02-20T22:43:37Z

    在 MVVM 模式下,VM 对象无法知道窗口的任何信息,这超出了它的职责范围。将 Handle 的接收留在窗口类中是正确的。

    但已经可以使用 UsbHid 将其取出到 VM 中。顺便问一下,为什么需要两个事件?

    protected override void OnSourceInitialized(EventArgs e) {
        base.OnSourceInitialized(e);
    
        ((ISomeViewModel)DataSource).Source = (HwndSource)PresentationSource.FromVisual(this);
    }
    

    只是不要忘记对任何属性的赋值都可能发生多次,这必须正确处理(即,您必须在添加新钩子之前删除旧钩子,等等)。


    作为替代方案,您可以使用 MVP 模式。与 ViewModel 不同,Presenter 有权了解视图。因此,Presenter 可以订阅 SourceInitialized 事件。

    或者,对于代码重用,尝试使用行为(Behavior)是有意义的:

    <Window ...>
    
      <i:Behaviors>
        <ctrl:UsbHidListener ViewModel="{Binding ...}" />
      </i:Behaviors>
    
    • 0

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    Python 3.6 - 安装 MySQL (Windows)

    • 1 个回答
  • Marko Smith

    C++ 编写程序“计算单个岛屿”。填充一个二维数组 12x12 0 和 1

    • 2 个回答
  • Marko Smith

    返回指针的函数

    • 1 个回答
  • Marko Smith

    我使用 django 管理面板添加图像,但它没有显示

    • 1 个回答
  • Marko Smith

    这些条目是什么意思,它们的完整等效项是什么样的

    • 2 个回答
  • Marko Smith

    浏览器仍然缓存文件数据

    • 1 个回答
  • Marko Smith

    在 Excel VBA 中激活工作表的问题

    • 3 个回答
  • Marko Smith

    为什么内置类型中包含复数而小数不包含?

    • 2 个回答
  • Marko Smith

    获得唯一途径

    • 3 个回答
  • Marko Smith

    告诉我一个像幻灯片一样创建滚动的库

    • 1 个回答
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Алексей Шиманский 如何以及通过什么方式来查找 Javascript 代码中的错误? 2020-08-03 00:21:37 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    user207618 Codegolf——组合选择算法的实现 2020-10-23 18:46:29 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5