Pourquoi certaines des réponses sur cette page sont fausses!
Essentiellement:
- La fenêtre ne doit pas capturer le focus loin de toute autre fenêtre lorsqu'elle s'active;
- La fenêtre ne doit pas activer son parent lorsqu'elle est affichée;
- La fenêtre doit être compatible avec Citrix.
Solution MVVM
Ce code est 100% compatible avec Citrix (pas de zones vides de l'écran). Il est testé avec WPF normal et DevExpress.
Cette réponse est destinée à tout cas d'utilisation où nous voulons une petite fenêtre de notification qui est toujours en face des autres fenêtres (si l'utilisateur le sélectionne dans les préférences).
Si cette réponse semble plus complexe que les autres, c'est parce qu'elle est robuste, au niveau de l'entreprise. Certaines des autres réponses sur cette page sont simples, mais ne fonctionnent pas réellement.
XAML - Propriété attenante
Ajoutez cette propriété attachée à n'importe quelle UserControl
dans la fenêtre. La propriété attenante:
- Attendez que l'
Loaded
événement soit déclenché (sinon il ne peut pas rechercher dans l'arborescence visuelle pour trouver la fenêtre parent).
- Ajoutez un gestionnaire d'événements qui garantit que la fenêtre est visible ou non.
À tout moment, vous pouvez définir la fenêtre devant ou non, en inversant la valeur de la propriété attachée.
<UserControl x:Class="..."
...
attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
"{Binding EnsureWindowInForeground, Mode=OneWay}">
C # - Méthode d'assistance
public static class HideAndShowWindowHelper
{
/// <summary>
/// Intent: Ensure that small notification window is on top of other windows.
/// </summary>
/// <param name="window"></param>
public static void ShiftWindowIntoForeground(Window window)
{
try
{
// Prevent the window from grabbing focus away from other windows the first time is created.
window.ShowActivated = false;
// Do not use .Show() and .Hide() - not compatible with Citrix!
if (window.Visibility != Visibility.Visible)
{
window.Visibility = Visibility.Visible;
}
// We can't allow the window to be maximized, as there is no de-maximize button!
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
window.Topmost = true;
}
catch (Exception)
{
// Gulp. Avoids "Cannot set visibility while window is closing".
}
}
/// <summary>
/// Intent: Ensure that small notification window can be hidden by other windows.
/// </summary>
/// <param name="window"></param>
public static void ShiftWindowIntoBackground(Window window)
{
try
{
// Prevent the window from grabbing focus away from other windows the first time is created.
window.ShowActivated = false;
// Do not use .Show() and .Hide() - not compatible with Citrix!
if (window.Visibility != Visibility.Collapsed)
{
window.Visibility = Visibility.Collapsed;
}
// We can't allow the window to be maximized, as there is no de-maximize button!
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
}
window.Topmost = false;
}
catch (Exception)
{
// Gulp. Avoids "Cannot set visibility while window is closing".
}
}
}
Usage
Pour l'utiliser, vous devez créer la fenêtre dans votre ViewModel:
private ToastView _toastViewWindow;
private void ShowWindow()
{
if (_toastViewWindow == null)
{
_toastViewWindow = new ToastView();
_dialogService.Show<ToastView>(this, this, _toastViewWindow, true);
}
ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}
private void HideWindow()
{
if (_toastViewWindow != null)
{
HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
}
}
Liens supplémentaires
Pour obtenir des conseils sur la façon de garantir qu'une fenêtre de notification revient toujours sur l'écran visible, consultez ma réponse: dans WPF, comment déplacer une fenêtre sur l'écran si elle est hors de l'écran? .