2013-05-07 189 views
4

我正試圖在WPF的SizeChanged事件窗口中處理一些事情。我有一些自定義代碼,我需要執行後用戶完成調整窗口的大小,不幸的是,我沒有遇到過這種情況,所以我創建了一個使用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,但只有在窗口框架內單擊鼠標時纔會觸發窗口句柄。有沒有類似的事件可以插入適用於窗口句柄的鼠標?或者任何人都可以爲我遇到的問題想出一個合適的解決方法?

回答

2

Windows發送一條專用消息來通知窗口模態大小/移動循環已退出。 WM_EXITSIZEMOVE,當用戶放開鼠標按鈕或按下Escape時觸發。但是,是的,WPF不公開它。谷歌「wpf wm_exitsizemove」找到你想要的互操作代碼。一個好看的打擊是this blog post

+0

啊,忘了這一點......這可能是比上面我嘗試一個更簡潔的方法。 :) – JerKimball 2013-05-07 16:36:35

+0

我可能應該提到我實際上有一些工作代碼使用互操作服務,但希望找到一些不太沉重的東西......它很難在代碼審查中解釋爲什麼我需要拉低級別的窗口東西對於看起來應該如此微不足道的東西。不過謝謝,博客文章是一個很好的閱讀。 – 2013-05-07 17:03:46

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