当前位置:  开发笔记 > 编程语言 > 正文

在WPF中为窗口打开一个窗口

如何解决《在WPF中为窗口打开一个窗口》经验,为你挑选了9个好方法。

如何将我的WPF应用程序带到桌面的前端?到目前为止,我已经尝试过:

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

这些都没有Marshal.GetLastWin32Error()成功(说这些操作成功完成,每个定义的P/Invoke属性都有SetLastError=true).

如果我创建一个新的空白WPF应用程序,并SwitchToThisWindow使用计时器调用,它完全按预期工作,所以我不知道为什么它不能在我的原始情况下工作.

编辑:我正在与全球热键一起做这个.



1> Morten Chris..:
myWindow.Activate();

尝试将窗口置于前台并激活它.

这应该是诀窍,除非我误解了你想要永远在行为上.在这种情况下,你想要:

myWindow.TopMost = true;


我只是使用myWindow.Show(),有时它不在顶部.之后我立刻打电话给myWindow.Activate()并且它有效.
有时,Activate在Windows XP上不起作用.我推荐@Matthew Xavier的回答.
实际上可以这样做:`if(myWindow.WindowState == WindowState.Minimized)myWindow.WindowState = WindowState.Normal;`奇怪的是,它还会保留任何最大化的窗口,而不是将它们恢复到正常状态.

2> Jader Dias..:

我找到了一个将窗口置于顶部的解决方案,但它的行为与普通窗口相同:

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


不要使用`Window.Focus()`.这将使焦点远离用户当前在文本框中输入的内容,这对最终用户来说是极其令人沮丧的.没有它,上面的代码工作得很好.
在我的例子中,Window.Activate()和Window.Focus()就足够了.设置Window.TopMost是不必要的.

3> 小智..:

如果您在第一次加载时需要窗口在前面,那么您应该使用以下内容:

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

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



4> Hertzel Guin..:

要使其快速复制粘贴 -
使用此类' DoOnProcess方法将进程'主窗口移动到前台(但不要从其他窗口窃取焦点)

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


+1这是唯一对我有用的答案.我有一个主应用程序和几个浮动从属窗口的应用程序.在激活其中任何一个时,所有其他窗口也应该被带到前面.但是没有激活/获得焦点,因为大多数答案表明:这是一场灾难,因为它使当前点击的窗口无法点击,因为突然另一个窗口获得焦点.

5> Zodman..:

我知道这个问题相当陈旧,但我刚刚遇到这个精确的场景,并希望分享我实施的解决方案.

正如本页评论中所提到的,所提出的一些解决方案不适用于XP,我需要在我的场景中支持.虽然我同意@Matthew Xavier的观点,即一般来说这是一个糟糕的用户体验,但有时候它完全是一个可信的用户体验.

将WPF窗口置于顶端的解决方案实际上是通过我用来提供全局热键的相同代码提供给我的.Joseph Cooney撰写的博客文章包含指向包含原始代码的代码示例的链接.

我已经清理并修改了一些代码,并将其作为System.Windows.Window的扩展方法实现.我已经在XP 32位和Win7 64位上进行了测试,两者都正常工作.

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

        /// 
        /// Activate a window from anywhere by attaching to the foreground window
        /// 
        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
    }
}

我希望这段代码可以帮助遇到这个问题的其他人.



6> Matthew Xavi..:

如果用户正在与另一个应用程序进行交互,则可能无法将您的应用程序置于最前面.作为一般规则,如果该进程已经是前台进程,则进程只能设置前台窗口.(Microsoft记录了SetForegroundWindow() MSDN条目中的限制.)这是因为:

    用户"拥有"前景.例如,如果另一个程序在用户输入时偷走了前台,至少打断了她的工作流程,并且可能导致意外后果,因为她对一个应用程序的击键被犯罪者误解,直到她注意到更改,这将是非常烦人的.

    想象一下,两个程序中的每一个都会检查它的窗口是否为前景,并尝试将其设置为前景(如果不是).一旦第二个程序运行,计算机就会变得无用,因为前台在每个任务切换时都会在两个程序之间反弹.



7> Seth..:

我遇到了类似的问题,WPF应用程序通过Shell对象从Access应用程序调用.

我的解决方案如下 - 适用于XP和Win7 x64,应用程序编译为x86目标.

我宁愿这样做比模拟一个alt-tab.

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



8> Jamaxack..:

我知道这是迟到的答案,可能对研究人员有帮助

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



9> Contango..:

为什么这个页面上的一些答案是错误的!

任何使用的答案window.Focus()都是错误的.

为什么?如果弹出通知消息,window.Focus()则会将焦点从用户当时键入的内容中移开.这对最终用户来说是极其令人沮丧的,特别是如果弹出窗口经常发生的话.

任何使用的答案window.Activate()都是错误的.

为什么?它还可以使任何父窗口可见.

任何省略的答案window.ShowActivated = false都是错误的.

为什么?当消息弹出时,它将从另一个窗口抓住焦点,这非常烦人!

任何不用于Visibility.Visible隐藏/显示窗口的答案都是错误的.

为什么?如果我们使用Citrix,如果窗口在关闭时没有折叠,它将在屏幕上留下一个奇怪的黑色矩形保持.因此,我们不能使用window.Show()window.Hide().

实质上:

当窗口激活时,窗口不应将焦点从任何其他窗口移开;

窗口显示时不应激活其父窗口;

该窗口应与Citrix兼容.

MVVM解决方案

此代码与Citrix 100%兼容(屏幕没有空白区域).它使用普通WPF和DevExpress进行测试.

此答案适用于我们想要一个始终位于其他窗口前面的小通知窗口的任何用例(如果用户在首选项中选择此窗口).

如果这个答案看起来比其他答案更复杂,那是因为它是健壮的企业级代码.此页面上的其他一些答案很简单,但实际上并不起作用.

XAML - 附属财产

将此附加属性添加到UserControl窗口中的任何属性.附属物业将:

等到Loaded事件被触发(否则它无法查找可视树以查找父窗口).

添加一个事件处理程序,以确保窗口是否可见.

在任何时候,您都可以通过翻转附加属性的值将窗口设置在前面或不前面.


C# - 助手方法

public static class HideAndShowWindowHelper
{
    /// 
    ///     Intent: Ensure that small notification window is on top of other windows.
    /// 
    /// 
    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".
        }
    }

    /// 
    ///     Intent: Ensure that small notification window can be hidden by other windows.
    /// 
    /// 
    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".
        }
    }
}

用法

要使用它,您需要在ViewModel中创建窗口:

private ToastView _toastViewWindow;
private void ShowWindow()
{
    if (_toastViewWindow == null)
    {
        _toastViewWindow = new ToastView();
        _dialogService.Show(this, this, _toastViewWindow, true);
    }
    ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
    HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}

private void HideWindow()
{
    if (_toastViewWindow != null)
    {
        HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
    }
}

其他链接

有关如何确保通知窗口始终返回可见屏幕的提示,请参阅我的答案:在WPF中,如果窗口离开屏幕,如何将窗口移动到屏幕上?.


"企业级代码"和几行后来`catch(Exception){}`.是的正确...它使用的答案甚至没有在`_dialogService`或`ShiftWindowOntoScreenHelper`中显示.另外要求在viewmodel端创建窗口(这基本上打破了整个MVVM模式)......
推荐阅读
有风吹过best
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有