【问题标题】:Simple solution to discard ui events in winforms?在winforms中丢弃ui事件的简单解决方案?
【发布时间】:2015-04-10 09:38:12
【问题描述】:

上下文

在深入探讨这个问题之前,我首先需要指出我正在尝试在 winforms 应用程序中单击某个按钮时显示一个 matlab 模态图。

用于显示图形的matlab代码很简单,在matlab环境中运行良好(即图形是模态的,我无法按预期点击其他任何地方):

function [] = ShowModalDlg()
%[
    % Create a modal figure
    fig = figure('WindowStyle', 'modal');

    % Add some drawings in it
    membrane();

    % Block execution until figure gets closed.
    uiwait(fig);
%]

将 matlab 代码编译为 .NET 并将其集成到我的 winforms 应用程序中也很容易(只需使用 Matlab Compiler SDK):

private void onBtnClick(object sender, EventArgs e)
{
    matlabComponent.ShowModalDlg();
} 

问题

在我的 winforms 应用程序中单击按钮时,似乎一切正常

  • matlab 图形按预期弹出。
  • 图形停留在顶部,我无法单击其他任何位置(即模态行为)。
  • winforms 线程真正阻塞在matlabComponent.ShowModalDlg() 中,直到关闭之前的图以继续执行下一行代码。

但是,因为有一个但是,就像winform应用程序仍在继续排队UI事件,当我关闭matlab图形时,它们都被处理了一排。例如,在显示 matlab 图形时,如果我尝试移动按住按钮的 winform,则没有任何反应,但只要我关闭图形,下面的 winform 就会移动!!

我怀疑 matlab 端使用不同的调度模型或其他任何东西(这是后台的 java)......无论如何我想阻止 winforms 来解决这个问题,例如:

private void onBtnClick(object sender, EventArgs e)
{
    using(var oo = new DiscardUIEvents(this))
    {
        matlabComponent.ShowModalDlg();
    }
}  

这可能吗?

【问题讨论】:

    标签: .net winforms matlab modal-dialog


    【解决方案1】:

    您可以通过使用 Windows API 拦截事件来实现您所需要的。 看看this,它使用 Windows API 并防止用户手动移动表单。因此,您可以根据自己的目的进行调整。

    编辑

    尝试将此代码添加到您的表单中,并在启动对话框之前/之后在单击事件处理程序中设置 _controlsEnabled。这应该可以防止表单被移动。 (你显然必须改进它以迎合你想忽略的所有事件)。

        private void onBtnClick(object sender, EventArgs e)
        {
            _controlsEnabled = false;
                matlabComponent.ShowModalDlg();
            _controlsEnabled = true;
        } 
    
        private bool _controlsEnabled = true;
    
        protected override void WndProc(ref Message m)
        {
                const int WM_SYSCOMMAND = 0x0112;
                const int SC_MOVE = 0xF010;
    
                switch (m.Msg)
                {
                    case WM_SYSCOMMAND:
                        if (!_controlsEnabled)
                        {
                             int command = m.WParam.ToInt32() & 0xfff0;
                             if (command == SC_MOVE)
                                 return;
                        }
                        break;
                }
                base.WndProc(ref m);
        }
    

    【讨论】:

    • 谢谢! :) .. 不幸的是,只要在matlabComponent.ShowModalDlg() 中阻塞了winform 线程,只有在离开onBtnClick 之后才会调用WndProc 覆盖来处理排队消息(_controlsEnabled 已经恢复为真)...我不'不知道我是否可以像这样覆盖消息排队(或至少在离开matlabComponent.ShowModalDlg()时清除队列中的一些消息)。
    • 似乎我可以通过GetInputStateGetQueueStatus 找到我想要的消息,但不知道我是否可以进一步加入队列以删除它们。
    • 嗯......从你的想法谷歌搜索我终于想到了PeekMessage,让我从队列中删除不需要的消息。我会发布一个答案。谢谢!
    【解决方案2】:

    从@DotNetHitMan 的答案谷歌搜索,我终于找到了PeekMessage,它让我在离开 matlab 代码时从 windows 队列中删除不需要的消息,所以很容易:

    private void onBtnClick(object sender, EventArgs e)
    {
        // Call matlab
        matlabComponent.ShowModalDlg();
    
        // Remove unwanted messages from the queue
        NativeMessage msg;
        while (PeekMessage(out msg, new HandleRef(this, this.Handle), WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)); // Remove mouse messages
        while (PeekMessage(out msg, new HandleRef(this, this.Handle), WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)); // Remove keyboard messages
    }
    

    注意:PeekMessageNativeMessage 互操作的语法可以从 here 读取。

    编辑

    这是将事物重构为using 语句的代码:

    using System;
    using System.Drawing;
    using System.Runtime.InteropServices;
    
    /// <summary>Allows discarding keyboard and mouse events while thread is blocked in executing some code while its windows message queue is continuing to accumulate events.</summary>
    ///<example>If you don't disable events while showing matlab modal dialog, events will continue to accumulate in message queue and will be processed after modal dialog is closed (i.e. not the behaviour one expects for a modal dialog).</example>
    public class DiscardUiEvents : IDisposable
    {
        /// <summary>Create new discard object.</summary>
        /// <param name="hr">Reference to the control that need to block its events.</param>
        /// <remarks>
        /// Must be used like this:
        /// 
        ///    using(new DiscardUiEvent(new HandleRef(myControl, myControl.Handle)))
        ///    {
        ///         matlabCompiledCode.ShowSomeModalFigure();
        ///    }
        /// </remarks>
        public DiscardUiEvents(HandleRef hr)
        {
            this.hr = hr;    
        }
    
        /// <summary>Dispose discard object.</summary>
        public void Dispose()
        {
            if (disposed) { return; }
    
            NativeMessage msg;
            while (PeekMessage(out msg, hr, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE)) { /* Remove all mouse messages */ }
            while (PeekMessage(out msg, hr, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) { /* Remove all keyboard messages */ }
        }
    
        private readonly HandleRef hr; 
        private bool disposed = false;
    
        private const UInt32 PM_REMOVE = 0x0001;
        private const UInt32 WM_MOUSEFIRST = 0x0200;
        private const UInt32 WM_MOUSELAST = 0x020D;
        private const UInt32 WM_KEYFIRST = 0x0100;
        private const UInt32 WM_KEYLAST = 0x0108;
    
        // ReSharper disable MemberCanBePrivate.Local
        [StructLayout(LayoutKind.Sequential)]
        private struct NativeMessage
        {            
            public IntPtr handle;
            public UInt32 msg;
            public IntPtr wParam;
            public IntPtr lParam;
            public UInt32 time;
            public Point p;            
        }
        // ReSharper restore MemberCanBePrivate.Local
    
        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool PeekMessage(out NativeMessage lpMsg, HandleRef hWnd, uint wMsgFilterMin, uint wMsgFilterMax, uint wRemoveMsg);
    }
    

    可以这样使用:

    using(new DiscardUiEvent(new HandleRef(myControl, myControl.Handle)))
    {
        matlabCompiledCode.ShowSomeModalFigure();
    }
    

    【讨论】:

      猜你喜欢
      • 2010-09-05
      • 2012-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-28
      • 2010-11-28
      相关资源
      最近更新 更多