在Visual Studio中未打开时,“开始”菜单将覆盖窗口

时间:2016-12-06 04:49:35

标签: c# .net wpf

我创建了一个使用WPF的窗口,我希望我的窗口始终显示在顶部,所以我只是为它创建一个线程:

System.Threading.Tasks.Task.Factory.StartNew(() =>
{
      for (;;)
      {
         System.Threading.Thread.Sleep(3000);

         this.Dispatcher.BeginInvoke(new Action(() =>
         {
               this.Activate();
               this.Topmost = true;
         }));
      }

   });
}

这将确保我的窗口每隔3秒就会显示一次。

当我在Visual Studio 2015下打开它时,一切正常,即使我打开“开始”菜单,它也会关闭开始菜单并将窗口置于顶部。但是当我不使用时Visual Studio打开应用程序(只需双击打开应用程序),当我打开开始菜单时,窗口只是闪烁,不显示在顶部。我想念的是什么?我如何让它像在Visual Studio 2015下打开应用程序一样工作(我在Win10上测试过)?

3 个答案:

答案 0 :(得分:1)

编辑:我在某种程度上错过了标题中涉及的内容。我后来提出的观点是" 不要这样做"仍然是正确的。它可能会给您的应用程序用户带来问题。

如果你真的需要,this answer可能是你正在寻找的那个。它讨论了如何在所有事物前面保持一个窗口。它仍然是一种解决方法(就像你问题的大多数答案一样)。

旧答案

我理解您的问题:您希望您的窗口保持在所有其他窗口之上。类似的功能可以在Ubuntu和适用于Window的Google Play音乐桌面应用程序中找到(见下文)。

enter image description here

要完成此操作,您只需向Topmost="True"添加Window,如下所示(查看最后一个属性)。

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Topmost="True">
</Window>

除非您的实际问题&#34;是两个窗口设置了该属性后会发生什么?&#34;然后我建议阅读this article(评论中引用的同一篇文章)。它陈述如下:

  

&#34;如何创建一个从未被任何其他窗口覆盖的窗口,甚至是其他最顶层的窗口?&#34;

     

想象一下,如果这是可能的,并想象两个程序是否做到了这一点。   程序A创建一个窗口,超级最顶层的窗口#34;程序也是如此   B.现在用户拖动两个窗口使它们重叠。什么   发生?你已经创造了一个逻辑上的不可能性。其中的一个   两个窗户必须在另一个之上,与想象中的相矛盾   &#34;超最上面的&#34;特征

如果您的功能真的如此,我建议:不要这样做。所有其他解决方案都是一种解决方法,可能会给您的应用程序的消费者带来问题。

答案 1 :(得分:0)

我会用互操作来做这件事。

public class Interop
{
    [DllImport("user32.dll")]
    public static extern bool SetForegroundWindow(IntPtr hWnd);

    [DllImport("user32.dll")]
    public static extern bool ShowWindow(IntPtr hwind, int cmd);


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

    public static IntPtr GetWindowHandle(Window window)
    {
        return new WindowInteropHelper(window).Handle;
    }
}

然后使用计时器:

private void Tick(object state)
    {

        this.Dispatcher.Invoke(() =>
        {
             IntPtr window = Interop.GetWindowHandle(this);
             IntPtr focused = Interop.GetForegroundWindow();
            if (window != focused)
            {
                Interop.SetForegroundWindow(window);
                                      // Command 5 for show
                Interop.ShowWindow(window, 5);
            }
        });
    }

Code from

关于startmenu的部分问题,只需添加组策略即可。

或者你可以与'FindWindowEx'进行互操作以找到开始按钮并禁用它。

答案 2 :(得分:0)

我同意Jonas的回答,但会修改它以使用事件而不是计时器。

    /// Get the topmost window handle
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();

    /// Trigger event when topmost window changed
    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr hmodWinEventProc, TopmostWindowChangedDelegate lpfnWinEventProc, uint idProcess, uint idThread, uint dwFlags);

    /// Set the topmost window
    [DllImport("user32.dll")]
    private static extern bool SetForegroundWindow(IntPtr hWnd);

    /// Show a window
    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hwind, int cmd);

    // Constant variables for topmost window changed event
    private const uint WINEVENT_OUTOFCONTEXT = 0;
    private const uint EVENT_SYSTEM_FOREGROUND = 3;

    /// Keep track of the last topmost window with a name
    private static IntPtr topWinHandle { get; set; }

    /// Implementation of topmost window changed delegate
    private TopmostWindowChangedDelegate TopmostWindowChanged { get; set; }

然后在您的一个启动方法中设置处理程序

    // Set topmost window changed event handler
    TopmostWindowChanged = new TopmostWindowChangedDelegate(WinEventProc);

    // Set event hook for topmost window changed
    IntPtr hook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero, TopmostWindowChanged, 0, 0, WINEVENT_OUTOFCONTEXT);

然后当其他最顶层的更改

时,将窗口移到最顶层
    /// Make sure this window stays on top
    public void WinEventProc(IntPtr hWinEventHook, uint eventType, IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
    {
        // Get current window name from handle
        IntPtr handle = GetForegroundWindow();

        if(handle != YOUR_WINDOW'S_HANDLE)
        {
             // Move your window back to the top
             SetForegroundWindow(YOUR_WINDOW'S_HANDLE);
             ShowWindow(YOUR_WINDOW'S_HANDLE, 5); 
        }
    }