Pergunta

Como posso trazer minha aplicação WPF para a frente da área de trabalho? Até agora eu tentei:

SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);

SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);

Nenhum dos quais estão fazendo o trabalho (Marshal.GetLastWin32Error() está dizendo essas operações concluídas com êxito, eo P / atributos Invoke para cada definição tem SetLastError=true).

Se eu criar um novo aplicativo em branco WPF, e SwitchToThisWindow chamada com um temporizador, ele funciona exatamente como o esperado, então eu não sei por que ele não está funcionando no meu caso originais.

Editar :. Estou fazendo isso em conjunto com uma tecla de atalho globais

Foi útil?

Solução 11

Bem, eu descobri um trabalho em torno. Eu estou fazendo a chamada a partir de um gancho de teclado usado para implementar uma tecla de atalho. A chamada funciona como esperado se eu colocá-lo em um BackgroundWorker com uma pausa. É um truque, mas não tenho idéia porque ele não estava funcionando originalmente.

void hotkey_execute()
{
    IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += new DoWorkEventHandler(delegate
        {
            Thread.Sleep(10);
            SwitchToThisWindow(handle, true);
        });
    bg.RunWorkerAsync();
}

Outras dicas

myWindow.Activate();

As tentativas para trazer a janela para o primeiro plano e ativa.

Isso deve fazer o truque, a menos que eu entendi mal e você quer sempre no comportamento Top. Nesse caso, você quer:

myWindow.TopMost = true;

Eu encontrei uma solução que traz a janela para o topo, mas ele se comporta como uma janela normal:

if (!Window.IsVisible)
{
    Window.Show();
}

if (Window.WindowState == WindowState.Minimized)
{
    Window.WindowState = WindowState.Normal;
}

Window.Activate();
Window.Topmost = true;  // important
Window.Topmost = false; // important
Window.Focus();         // important

No caso de precisar a janela para a frente a primeira vez que ele carrega, então você deve usar o seguinte:

private void Window_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
}

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}

Para fazer este uma cópia rápida e colar um -
Use esta classe método DoOnProcess ao processo de movimentação janela principal para primeiro plano (mas não roubar o foco de outras janelas)

public class MoveToForeground
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);

    const int SWP_NOMOVE        = 0x0002;
    const int SWP_NOSIZE        = 0x0001;            
    const int SWP_SHOWWINDOW    = 0x0040;
    const int SWP_NOACTIVATE    = 0x0010;
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    public static void DoOnProcess(string processName)
    {
        var allProcs = Process.GetProcessesByName(processName);
        if (allProcs.Length > 0)
        {
            Process proc = allProcs[0];
            int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
            // Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
            SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
        }
    }
}

HTH

Eu sei que esta questão é um pouco velho, mas eu acabei de se deparar com este cenário precisa e queria compartilhar a solução que eu tenho implementado.

Como mencionado na comentários nesta página, várias das soluções propostas não funcionam no XP, que eu preciso para apoiar no meu cenário. Enquanto eu concordo com o sentimento por @Matthew Xavier que, geralmente, esta é uma prática UX ruim, há momentos em que é inteiramente uma UX plausable.

A solução para trazer uma janela WPF ao topo foi realmente fornecido para mim pelo mesmo código que estou usando para fornecer a tecla de atalho global. um blog artigo de Joseph Cooney contém um link href="https://bitbucket.org/josephcooney/learnwpf.com.samples"> que contém o código original.

Eu já limpou e modificou o código um pouco, e implementou-lo como um método de extensão para System.Windows.Window. Eu testei isso no XP de 32 bits e Win7 64 bits, sendo que ambos funcionam corretamente.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace System.Windows
{
    public static class SystemWindows
    {
        #region Constants

        const UInt32 SWP_NOSIZE = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 SWP_SHOWWINDOW = 0x0040;

        #endregion

        /// <summary>
        /// Activate a window from anywhere by attaching to the foreground window
        /// </summary>
        public static void GlobalActivate(this Window w)
        {
            //Get the process ID for this window's thread
            var interopHelper = new WindowInteropHelper(w);
            var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);

            //Get the process ID for the foreground window's thread
            var currentForegroundWindow = GetForegroundWindow();
            var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            //Attach this window's thread to the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            //Set the window position
            SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

            //Detach this window's thread from the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            //Show and activate the window
            if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
            w.Show();
            w.Activate();
        }

        #region Imports

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion
    }
}

Espero que este código ajuda os outros que se deparam com este problema.

Se o usuário está interagindo com outro aplicativo, pode não ser possível trazer seu para a frente. Como regra geral, um processo só pode esperar para definir a janela de primeiro plano se esse processo já é o processo em primeiro plano. (Microsoft documenta as restrições no SetForegroundWindow () . entrada MSDN) Isto é porque:

  1. O usuário "dono" de primeiro plano. Por exemplo, seria extremamente irritante se outro programa roubou o primeiro plano quando o usuário está digitando, pelo menos interrompendo-a de fluxo de trabalho, e possivelmente causar consequências indesejadas como seu teclas digitadas significou para uma aplicação são mal interpretados pelo autor do crime até que ela percebe a mudança .
  2. Imagine que cada um dos dois cheques programas para ver se sua janela é o primeiro plano e as tentativas para defini-lo para o primeiro plano se ele não é. Assim que o segundo programa está em execução, o computador torna-se inútil como os saltos de primeiro plano entre os dois em cada alternância de tarefas.

Eu tive um problema semelhante com uma aplicação WPF que é invocado a partir de um aplicativo do Access através do objeto Shell.

A minha solução é abaixo -. Trabalhos em XP e Win7 x64 com aplicativo compilados a meta x86

Eu prefiro fazer isso do que simular uma aba de alt.

void Window_Loaded(object sender, RoutedEventArgs e)
{
    // make sure the window is normal or maximised
    // this was the core of the problem for me;
    // even though the default was "Normal", starting it via shell minimised it
    this.WindowState = WindowState.Normal;

    // only required for some scenarios
    this.Activate();
}

Eu sei que esta é a resposta final, talvez útil para investigadores

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }

Por que algumas das respostas nesta página está errado!

  • Qualquer resposta que usos window.Focus() está errado.

    • Por quê? Se uma mensagem de notificação aparece, window.Focus() vai agarrar o foco de tudo o que o usuário está digitando no momento. Isso é incrivelmente frustrante para os usuários finais, especialmente se os popups ocorrem com bastante freqüência.
  • Qualquer resposta que usos window.Activate() está errado.

    • Por quê? Isso fará com que todas as janelas pai visível também.
  • Qualquer resposta que omite window.ShowActivated = false está errado.
    • Por quê? Ele vai pegar o foco de outra janela quando a mensagem aparece que é muito chato!
  • Qualquer resposta que não usa Visibility.Visible para ocultar / mostrar a janela está errado.
    • Por quê? Se estamos usando Citrix, se a janela não é recolhido quando ele é fechado, ele vai deixar um porão retangular preta estranho na tela. Assim, não podemos usar window.Show() e window.Hide().

Essencialmente:

  • A janela não deve pegar o foco longe de qualquer outra janela quando ele ativa;
  • A janela não deve ativar seu pai quando ele é mostrado;
  • A janela deve ser compatível com Citrix.

MVVM Solução

Este código é 100% compatível com Citrix (há áreas em branco da tela). Ele é testado tanto com WPF normal e DevExpress.

Esta resposta destina-se a qualquer caso de uso onde queremos uma pequena janela de notificação que está sempre na frente de outras janelas (se o usuário seleciona este nas preferências).

Se esta resposta parece mais complexa do que os outros, é porque ela é robusta, código de nível empresarial. Algumas das outras respostas nesta página são simples, mas na verdade não trabalho.

XAML - Anexado Propriedade

Adicione esta propriedade anexada a qualquer UserControl dentro da janela. A propriedade anexada irá:

  • Aguarde até que o evento Loaded é disparado (caso contrário ele não pode olhar para cima a árvore visual para encontrar a janela pai).
  • Adicionar um manipulador de eventos que garante que a janela é visível ou não.

A qualquer momento, você pode definir a janela para estar na frente ou não, lançando o valor da propriedade anexada.

<UserControl x:Class="..."
         ...
         attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
             "{Binding EnsureWindowInForeground, Mode=OneWay}">

C # - Helper Método

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

Outras ligações

Para obter dicas sobre como garantir que uma janela de notificação sempre muda de volta para a tela visível, ver a minha resposta: no WPF, como mudar uma janela na tela, se é fora da tela? .

Bem, uma vez que este é um tema quente ... aqui é o que funciona para mim. Eu tenho erros se eu não fazê-lo desta maneira, porque Activate () irá erro fora em você se você não pode ver a janela.

Xaml:

<Window .... 
        Topmost="True" 
        .... 
        ContentRendered="mainWindow_ContentRendered"> .... </Window>

Codebehind:

private void mainWindow_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
    this.Activate();
    _UsernameTextBox.Focus();
}

Esta foi a única maneira para mim para obter a janela para mostrar no topo. Em seguida, ativá-lo assim que você pode digitar na caixa sem ter que foco conjunto com o mouse. Control.Focus () não vai funcionar a menos que a janela está ativa ();

Para mostrar QUALQUER atualmente aberto importação janela aqueles DLL:

public partial class Form1 : Form
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);
    [DllImportAttribute("User32.dll")]
    private static extern int SetForegroundWindow(int hWnd);

e no programa Procuramos aplicativo com o título especificado (título gravação sem primeira letra (index> 0))

  foreach (Process proc in Process.GetProcesses())
                {
                    tx = proc.MainWindowTitle.ToString();
                    if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
                    {
                        tx = proc.MainWindowTitle;
                        hWnd = proc.Handle.ToInt32(); break;
                    }
                }
                hWnd = FindWindow(null, tx);
                if (hWnd > 0)
                {
                    SetForegroundWindow(hWnd);
                }

O problema pode ser que o segmento chamado seu código a partir do gancho não foi inicializado pelo tempo de execução assim que chamar métodos de tempo de execução não fazer o trabalho.

Talvez você poderia tentar fazer uma invocação de organizar seu código para o segmento interface do usuário para chamar o código que traz a janela para o primeiro plano.

Estes códigos vai funcionar bem todos os momentos.

No primeiro set o manipulador de eventos ativados em XAML:

Activated="Window_Activated"

Adicionar abaixo da linha para o seu bloco construtor da janela principal:

public MainWindow()
{
    InitializeComponent();
    this.LocationChanged += (sender, e) => this.Window_Activated(sender, e);
}

E dentro do manipulador de eventos ativados copiar este código:

private void Window_Activated(object sender, EventArgs e)
{
    if (Application.Current.Windows.Count > 1)
    {
        foreach (Window win in Application.Current.Windows)
            try
            {
                if (!win.Equals(this))
                {
                    if (!win.IsVisible)
                    {
                        win.ShowDialog();
                    }

                    if (win.WindowState == WindowState.Minimized)
                    {
                        win.WindowState = WindowState.Normal;
                    }

                    win.Activate();
                    win.Topmost = true;
                    win.Topmost = false;
                    win.Focus();
                }
            }
            catch { }
    }
    else
        this.Focus();
}

Estas medidas irão funciona bem e vai trazer para a frente todas as outras janelas em sua janela pais.

Se você está tentando ocultar a janela, por exemplo, você minimizar a janela, eu descobri que usando

    this.Hide();

irá escondê-lo corretamente, então simplesmente usando

    this.Show();

mostrará então a janela como o topo item mais uma vez.

Só queria acrescentar uma outra solução para esta questão. Esta implementação funciona para o meu cenário, onde Caliburn é responsável por exibir a janela principal.

protected override void OnStartup(object sender, StartupEventArgs e)
{
    DisplayRootViewFor<IMainWindowViewModel>();

    Application.MainWindow.Topmost = true;
    Application.MainWindow.Activate();
    Application.MainWindow.Activated += OnMainWindowActivated;
}

private static void OnMainWindowActivated(object sender, EventArgs e)
{
    var window = sender as Window;
    if (window != null)
    {
        window.Activated -= OnMainWindowActivated;
        window.Topmost = false;
        window.Focus();
    }
}

Lembre-se de não colocar o código que mostra que a janela dentro de um manipulador de PreviewMouseDoubleClick como a janela activa irá voltar para a janela que tratou o evento. Basta colocá-lo no manipulador de eventos MouseDoubleClick ou parar borbulhando por definição e.Handled para True.

No meu caso eu estava lidando com a PreviewMouseDoubleClick em um Listview e não estava arrumando a e.Handled = true, em seguida, disparou o evento bruxa MouseDoubleClick sentou-foco para a janela original.

Eu construí um método de extensão para fazer para facilitar a reutilização.

using System.Windows.Forms;
    namespace YourNamespace{
        public static class WindowsFormExtensions {
            public static void PutOnTop(this Form form) {
                form.Show();
                form.Activate();
            }// END PutOnTop()       
        }// END class
    }// END namespace

Chamada no construtor Form

namespace YourNamespace{
       public partial class FormName : Form {
       public FormName(){
            this.PutOnTop();
            InitalizeComponents();
        }// END Constructor
    } // END Form            
}// END namespace
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top