如何捕获结束调整大小窗口?

时间:2010-12-17 20:52:49

标签: c# wpf xaml resize window

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

5 个答案:

答案 0 :(得分:27)

WPF不提供仅在调整大小过程结束时触发的事件。 SizeChanged 是与窗口大小调整相关联的唯一事件 - 在调整大小过程中会多次触发。

完全破解是在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
}

答案 1 :(得分:13)

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

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

这将有效地限制SizeChanged事件,这样你的Size_Changed方法(在那里你可以执行自定义代码)将不会被执行,直到200毫秒(或者你想等待的时间长)没有另一个{{ 1}}事件被解雇。

SizeChanged

答案 2 :(得分:5)

您可以准确检测WPF窗口调整大小何时结束,并且您不需要计时器。当用户在窗口调整大小移动操作结束时释放鼠标左键时,本机窗口会收到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

这个和类似的技术解释为herehere

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

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

(注意:不要对此处突出显示的代码感到困惑,导致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

就是这样。

答案 3 :(得分:2)

没有计时器@Bohoo up提供了非常干净的解决方案,我只是将他的代码从vb.net修改为c#

     public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.Loaded += MainWindow_Loaded;
            }

            private void MainWindow_Loaded(object sender, RoutedEventArgs e)
            {
                // this two line have to be exactly onload
                HwndSource source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
                source.AddHook(new HwndSourceHook(WndProc));
            }


            const int WM_SIZING = 0x214;
            const int WM_EXITSIZEMOVE = 0x232;
            private static bool WindowWasResized = false;


            private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
            {
                if (msg == WM_SIZING)
                {

                    if (WindowWasResized == false)
                    {

                        //    'indicate the the user is resizing and not moving the window
                        WindowWasResized = true;
                    }
                }

                if (msg == WM_EXITSIZEMOVE)
                {

                    // 'check that this is the end of resize and not move operation          
                    if (WindowWasResized == true)
                    {

                        // your stuff to do 
                        Console.WriteLine("End");

                        // 'set it back to false for the next resize/move
                        WindowWasResized = false;
                    }
                }

                return IntPtr.Zero;
            }

    }

答案 4 :(得分:0)

对于带有Rx的UWP(System.Reactive)

'???.3???.???' or '?????.??' or '???.?????.????'