Por que algumas das respostas desta página estão erradas!
Essencialmente:
- A janela não deve desviar o foco de nenhuma outra janela quando for ativada;
- A janela não deve ativar seu pai quando é mostrada;
- A janela deve ser compatível com o Citrix.
Solução MVVM
Este código é 100% compatível com o Citrix (sem áreas em branco na tela). É testado com o WPF e o DevExpress normais.
Esta resposta é destinada a qualquer caso de uso em que desejamos uma pequena janela de notificação sempre à frente de outras janelas (se o usuário selecionar isso nas preferências).
Se essa resposta parece mais complexa que as outras, é porque é um código robusto no nível da empresa. Algumas das outras respostas nesta página são simples, mas na verdade não funcionam.
XAML - Propriedade anexada
Adicione esta propriedade anexada a qualquer uma UserControl
dentro da janela. A propriedade anexada irá:
- Aguarde até o
Loaded
evento seja disparado (caso contrário, ele não poderá procurar na árvore visual para encontrar a janela pai).
- Adicione um manipulador de eventos que garanta que a janela esteja visível ou não.
A qualquer momento, você pode definir a janela para ficar na frente ou não, invertendo o valor da propriedade anexada.
<UserControl x:Class="..."
...
attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
"{Binding EnsureWindowInForeground, Mode=OneWay}">
Método auxiliar
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".
}
}
}
Uso
Para usar isso, você precisa criar a janela no seu 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);
}
}
Links adicionais
Para obter dicas sobre como garantir que uma janela de notificação sempre volte para a tela visível, veja minha resposta: No WPF, como mudar uma janela para a tela se estiver fora da tela? .