-2

I have create a Window use WPF, I want to my Window always display on the top, So I just create a thread for it:

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

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

   });
}

This will make sure my window go to front in every 3 seconds.

And when I open it under Visual Studio 2015, all fine, even when I open the Start Menu, it will close start menu and bring the window on top.But when I'm not use Visual studio open the application(just double click open the application), when I open start menu, the Window just flickering, not display on the top. What I miss? and how do I let it work as like open the application under Visual Studio 2015(I'm tested on Win10)?

qakmak
  • 1,287
  • 9
  • 31
  • 62
  • if youre having an issue, its better to post your actual code not pseudo code, that will get you more help – Simon Price Dec 06 '16 at 08:56
  • You might want to read [what if two programs did this?](https://blogs.msdn.microsoft.com/oldnewthing/20050607-00/?p=35413) which does specifically mention programs trying to be "super-topmost" – Damien_The_Unbeliever Dec 08 '16 at 09:51
  • @Damien_The_Unbeliever, the problem is if you run it under visual studio all fine. I don't think that's the problem that start menu and my app conflict, if it would it will already conflict when I was running my app from visual studio. Also I'm sure there is no other window cover my app when run under visual studio, but run with myself, it just flickering, not go to the top. – qakmak Dec 08 '16 at 10:25
  • What you are trying to achieve is rude, dangerous and redundant. If the application is only for your use then it doesn't matter, so don't do it. If you expect others to use it then it is guaranteed that your application is not the most important one that the user has installed; they *do not* want your application to remain on top when they are trying to use their 'SaveALife' utility. Either way, don't do it. ...and really, really don't use a timer to do it on a different thread - that is so Windows XP. – Evil Dog Pie Dec 08 '16 at 13:49
  • @Maverik, I don't think I'm rude for anybody, I just explain it for some one lazy enough to not test my code and just use a sentence to confirmed I'm not put all code. If you are the one come to help your friend, it's ok, Maybe someone else would help me without arrogant and understanding, not come here for fight with me. – qakmak Dec 08 '16 at 16:14
  • @MikeofSST, Thank you for your good advice, I know it's dangerous, but in my scenario I still need to make sure my application on the top. But still thank you for your advice. – qakmak Dec 08 '16 at 16:18
  • @qakmak Well, if you absolutely must do it, rather than creating a new thread with a sleep delay, try putting your `Activate()` and `TopMost=true` code into a handler for the `Window.Deactivated` and `Application.Deactivated` events. – Evil Dog Pie Dec 08 '16 at 16:27
  • @MikeofSST, Actually I did it already, but still same result, currently the question sample code just for fix the problem, that's why I'm not put the other logic about `Visibility` or `Active`. now the problem is no matter I use which way to my application display on top. it will always flickering but not go to top when not run under visual studio. – qakmak Dec 08 '16 at 16:32

3 Answers3

1

EDIT: I somehow missed the point covered in the title. The point I make later of "Do not do it" still holds true though. It could cause problems for users of your application.

If you really need to though, this answer may be the one you are looking for. It discusses how to keep a window in front of everything. It is still a work around (just like most answers to your question).

Old Answer

I understand your problem as: you want your window to stay on top of all other windows. Similar functionality can be found in Ubuntu and The Google Play Music desktop application for Window's (see below).

enter image description here

To accomplish this, all you need to do is add Topmost="True" to your Window as demonstrated below (look at the last property).

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

Unless your actual problem "is what happens when two windows have that property set?" Then I would suggest reading this article (the same article that was referenced in the comments). It states the following:

"How do I create a window that is never covered by any other windows, not even other topmost windows?"

Imagine if this were possible and imagine if two programs did this. Program A creates a window that is "super-topmost" and so does Program B. Now the user drags the two windows so that they overlap. What happens? You've created yourself a logical impossibility. One of those two windows must be above the other, contradicting the imaginary "super-topmost" feature.

If that functionality is really what you are after, I would suggest: do not do it. All other solutions are a workaround and could cause problems for consumers of your application.

Community
  • 1
  • 1
JoshuaTheMiller
  • 2,582
  • 25
  • 27
  • 1
    Yes, your edited answer looks like the only way, need to a signed binary in trusted location. I tested and worked... Thank you. – qakmak Dec 14 '16 at 19:28
  • 1
    There are more enough detail of answer for someone also looking for:http://stackoverflow.com/a/14718834/1900498 – qakmak Dec 14 '16 at 20:31
0

I would have used interop to do this.

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

then use a timer:

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

And for the part of your problem regarding the startmenu, just add a group policy.

Or you can make a interop to ´FindWindowEx´ to find the startbutton and disable it.

  • But In Windows 10, start menu, Clock, Notification panel.... all will let it only flickering, not show up. (when run without VS2015) – qakmak Dec 14 '16 at 19:01
0

I agree with Jonas's answer but would modify it to use an event instead of a timer.

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

Then set up the handlers in one of your startup methods

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

And then move your window to topmost when the other topmost changes

    /// 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); 
        }
    }
brandonstrong
  • 628
  • 7
  • 21
  • Thank you for your such a good code, but unfortunately, on Windows 10...please just go to look at the comment which I leave for Jonas answers. – qakmak Dec 14 '16 at 19:03