4

SizeChanged目前,在处理Window 上的 WPF 事件时,我正试图跳过一些障碍。在用户完成调整窗口大小后,我需要执行一些自定义代码,不幸的是,我没有遇到任何事件,因此我创建了一个使用 Reactive Extensions 来限制 SizeChange 事件的解决方案:

IObservable<SizeChangedEventArgs> ObservableSizeChanges = Observable
    .FromEventPattern<SizeChangedEventArgs>(this, "SizeChanged")
    .Select(x => x.EventArgs)
    .Throttle(TimeSpan.FromMilliseconds(200));

IDisposable SizeChangedSubscription = ObservableSizeChanges
    .ObserveOn(SynchronizationContext.Current)
    .Subscribe(x => {
        Size_Changed(x);
    });

基本上,这样做是确保在调用我的自定义代码之前必须经过 200 毫秒的无 SizeChanged 事件。这工作正常但是我遇到了一个问题,如果用户将窗口句柄拖出并继续按住鼠标按钮,代码仍将被执行。我希望能够确保在鼠标按钮按下时无法执行自定义代码。我尝试插入,PreviewMouseLeftButtonDown但单击窗口句柄时不会触发,只有在窗口框架内单击鼠标时才会触发。是否有任何类似的事件可以插入适用于窗口句柄的鼠标按下?或者谁能​​想到一个合适的解决方法来解决我遇到的问题?

4

2 回答 2

2

Windows 发送专用消息通知窗口模态大小/移动循环已退出。WM_EXITSIZEMOVE,当用户松开鼠标按钮或按下 Escape 时触发。但是,是的,WPF 没有公开它。谷歌“wpf wm_exitsizemove”找到你想要的互操作代码。一篇好看的文章是这篇博文

于 2013-05-07T16:35:30.473 回答
1

这可能是矫枉过正,但要专门解决您的“我怎样才能确定鼠标按钮是否按下?” 问题,看看这个 P/Invoke 包装器:

public class ButtonObserver : IDisposable
{
    public struct MouseButtons
    {
        public bool LeftButton;
        public bool RightButton;
    }

    [DllImport("user32.dll")]
    static extern short GetAsyncKeyState(int vKey);
    private const int VK_LBUTTON = 0x01;
    private const int VK_RBUTTON = 0x02;

    private Task _pollTask = null;
    private Subject<MouseButtons> _pollBuffer = new Subject<MouseButtons>();
    private CancellationTokenSource _canceller;

    public IObservable<MouseButtons> PollMouse(int pollDelayMs)
    {
        if(_pollTask == null)
        {
            _canceller = new CancellationTokenSource();
            _pollTask = Task.Factory.StartNew(() =>
            {
                while(!_canceller.IsCancellationRequested)
                {
                    var mbLeft = GetAsyncKeyState(VK_LBUTTON) != 0;
                    var mbRight = GetAsyncKeyState(VK_RBUTTON) != 0;
                    _pollBuffer.OnNext(new MouseButtons{ LeftButton = mbLeft, RightButton = mbRight});
                    Thread.Sleep(pollDelayMs);
                }
            });            
        }
        return _pollBuffer;
    }

    public void Dispose()
    {
        _canceller.Cancel();
        _pollTask.Wait();
        _pollTask = null;
    }
}

您可以将其用作:

void Main()
{
    var buttonObs = new ButtonObserver();
    var buttons = buttonObs.PollMouse(100).Where(mb => mb.LeftButton);
    using(buttons.Subscribe(mb => Console.WriteLine("Left button down")))
    {
        Console.ReadLine();
    }
    buttonObs.Dispose();
}
于 2013-05-07T16:35:39.600 回答