如何捕获结束resize窗口?

我需要在WPF中捕获事件endresize。

WPF不提供仅在resize过程结束时触发的事件。 SizeChanged是与Window大小调整相关联的唯一事件 – 它将在resize过程中多次触发。

完全破解是在SizeChanged事件触发时不断设置计时器滴答。 然后计时器将无法勾选,直到调整结束并在那时进行一次处理。

public MyUserControl() { _resizeTimer.Tick += _resizeTimer_Tick; } DispatcherTimer _resizeTimer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 0, 1500), IsEnabled = false }; private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e) { _resizeTimer.IsEnabled = true; _resizeTimer.Stop(); _resizeTimer.Start(); } void _resizeTimer_Tick(object sender, EventArgs e) { _resizeTimer.IsEnabled = false; //Do end of resize processing } 

.NET的Reactive Extensions为处理标准事件模式提供了一些非常酷的function,包括能够限制事件。 我在处理大小更改事件时遇到了类似的问题,虽然解决方案仍然有点“hacky”,但我认为Reactive Extensions提供了一种更优雅的实现方式。 这是我的实施:

 IObservable ObservableSizeChanges = Observable .FromEventPattern(this, "SizeChanged") .Select(x => x.EventArgs) .Throttle(TimeSpan.FromMilliseconds(200)); IDisposable SizeChangedSubscription = ObservableSizeChanges .ObserveOn(SynchronizationContext.Current) .Subscribe(x => { Size_Changed(x); }); 

这将有效地限制SizeChanged事件,这样你的Size_Changed方法(你可以执行自定义代码)将不会被执行,直到200毫秒(或者你想等待的时间长)已经过去而没有触发另一个SizeChanged事件。

 private void Size_Changed(SizeChangedEventArgs e) { // custom code for dealing with end of size changed here } 

您可以准确检测WPF窗口resize何时结束,并且您不需要计时器。 当用户在窗口resize移动操作结束时释放鼠标左键时,本机窗口会收到WM_EXITSIZEMOVE消息。 WPF窗口没有收到此消息,因此我们需要连接一个将接收它的WndProc函数。 我们可以使用HwndSourceWindowInteropHelper来获取窗口句柄。 然后我们将钩子添加到我们的WndProc函数中。 我们将在窗口Loaded事件(vb.net代码)中执行所有操作:

 Dim WinSource As HwndSource Private Sub WindowLoaded_(sender As Object, e As RoutedEventArgs) WinSource = HwndSource.FromHwnd(New WindowInteropHelper(Me).Handle) WinSource.AddHook(New HwndSourceHook(AddressOf WndProc)) End Sub 

现在,在我们的WndProc ,我们将收听WM_EXITSIZEMOVE消息:

 Const WM_EXITSIZEMOVE As Integer = &H232 Private Function WndProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr If msg = WM_EXITSIZEMOVE Then DoWhatYouNeed() End If Return IntPtr.Zero End Function 

这里和这里解释了这种和类似的技术。

请注意,该函数应返回IntPtr.Zero。 此外,除了处理您感兴趣的特定消息之外,不要在此函数中执行任何操作。

现在, WM_EXITSIZEMOVE也在移动操作结束时发送,我们只对resize感兴趣。 有几种方法可以确定这是resize操作的结束。 我是通过收听WM_SIZING消息(在resize期间多次发送)并结合标志来完成的。 整个解决方案如下所示:

(注意:不要对此处突出显示的代码感到困惑,导致vb.net出错)

 Dim WinSource As HwndSource Const WM_SIZING As Integer = &H214 Const WM_EXITSIZEMOVE As Integer = &H232 Dim WindowWasResized As Boolean = False Private Sub WindowLoaded_(sender As Object, e As RoutedEventArgs) WinSource = HwndSource.FromHwnd(New WindowInteropHelper(Me).Handle) WinSource.AddHook(New HwndSourceHook(AddressOf WndProc)) End Sub Private Function WndProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr If msg = WM_SIZING Then If WindowWasResized = False Then 'indicate the the user is resizing and not moving the window WindowWasResized = True End If End If If msg = WM_EXITSIZEMOVE Then 'check that this is the end of resize and not move operation If WindowWasResized = True Then DoWhatYouNeed() 'set it back to false for the next resize/move WindowWasResized = False End If End If Return IntPtr.Zero End Function 

而已。