Comment saisir la fenêtre de fin de redimensionnement?
j'ai besoin d'attraper la fin de l'événement dans WPF.
3 réponses
WPF ne fournit pas un événement qui déclenche uniquement à la fin du processus de redimensionnement. SizeChanged est le seul événement associé au redimensionnement de fenêtre - et il se déclenchera plusieurs fois pendant le processus de redimensionnement.
un hack total serait de mettre constamment un ticking de minuterie quand l'événement SizeChanged se déclenche. Puis timer n'aura pas la chance de cocher jusqu'à ce que le redimensionnement se termine et à ce point faire votre traitement unique.
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
}
les Extensions réactives pour .NET offrent des capacités vraiment cool pour traiter les modèles d'événements standard, y compris la possibilité d'étouffer les événements. J'ai eu un problème similaire en traitant les événements de taille changée et bien que la solution soit encore un peu "hacky" je pense que les Extensions réactives fournit une façon beaucoup plus élégante de la mettre en œuvre. Voici mon oeuvre:
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);
});
cela va effectivement étrangler le SizeChanged
événement tel que votre méthode Size_Changed (où vous pouvez exécuter du code personnalisé) ne sera pas exécuté avant que 200 millisecondes (ou aussi longtemps que vous voulez attendre) ne soient passées sans un autre SizeChanged
événement étant tiré.
private void Size_Changed(SizeChangedEventArgs e) {
// custom code for dealing with end of size changed here
}
vous pouvez détecter exactement quand une fenêtre WPF redimensionnée s'est terminée, et vous n'avez pas besoin de minuterie. Une fenêtre native reçoit le WM_EXITSIZEMOVE
message lorsque l'utilisateur relâchez le bouton gauche de la souris à la fin d'une fenêtre redimensionner ou opération de déplacement. Une fenêtre WPF ne reçoit pas ce message, nous avons donc besoin de brancher un WndProc
fonction qui le recevra. Nous pouvons utiliser HwndSource
WindowInteropHelper
pour obtenir notre poignée de la fenêtre. Alors nous allons ajouter le crochet à notre WndProc
fonction. Nous ferons tout ce qui dans la fenêtre Loaded
événement (vb.net code):
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
Maintenant, dans notre WndProc
, nous allons écouter l' WM_EXITSIZEMOVE
message:
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
C'et une technique similaire est expliqué ici et ici.
Notez que la fonction doit retourner IntPtr.Zéro. De plus, ne faites rien dans cette func, sauf Gérer les messages spécifiques qui vous intéressent.
Maintenant, WM_EXITSIZEMOVE
est également envoyé à la fin d'une opération de déplacement, et nous nous intéressons uniquement à redimensionner. Il y a plusieurs façons de déterminer que c'était la fin de l'opération de redimensionnement. Je l'ai fait par l'écoute de l' WM_SIZING
message (envoyé plusieurs fois lors de redimensionnement), combiné avec un drapeau. Toute la solution ressemble à ceci:
(Note: Ne pas confondre avec la mise en évidence du code ici, car son mauvais pour 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
C'est ça.