WPF Always On Top

2019-01-10 22:17发布

问题:

Is it possible to make a window stay always on top even when other application is running on Fullscreen? I'm using right now TopMost = true but when other application is running on fullscreen mine becomes invisible. It's WindowStyle = None window by the way.

Edit: And do not let other window minimalize ofcourse

回答1:

This won't work 100% of the time, but it will improve the situation somewhat. You can set Topmost = true in the handler for the Window.Deactivated event:

private void Window_Deactivated(object sender, EventArgs e)
{
    Window window = (Window)sender;
    window.Topmost = true;
}

The Deactivated event will be called whenever your application loses focus (often when another application requests to be Topmost) and so this will reset your application on top after this.



回答2:

Try this solution from MSDN, it should work for you. In the Window Activated Event add the following code:

this.Width = System.Windows.SystemParameters.PrimaryScreenWidth;
this.Height = System.Windows.SystemParameters.PrimaryScreenHeight;
this.Topmost = true;
this.Top = 0;
this.Left=0;

in DeActivated Event add the following code

this.Topmost = true;
this.Activate();

Original post from MSDN



回答3:

If you want your application to stay on top of EVERYTHING (including the start interface in Windows 8, previously known as "Metro"), then you can specify UiAccess="True" in your manifest file. This is typically used by accessibility applications such as onscreen keyboards.

From memory you need to do 3 things;

  1. Request UiAccess="True"
  2. Sign your application's exe file with a recognised certificate. I obtained a free code signing certificate from Certum as my project is Open Source.
  3. Install your application to a "Trusted Location", which in my case was the program files directory. There is no official definition of "Trusted Location" that I could find.


回答4:

So I ran into the same requirement recently. It seems the top rated answer as well as the second didn't properly work for me. I've found a solution that seems to work flawlessly and somewhat adheres to best practice using MVVM.

Using the below forces the window to the top and never lapses on change like the other solutions.

Step 1: I created a simple state manager class for my main client window. I used INotifyPropertyChanged to keep property in sync when using a direct binding to my window. (very important)

public class ClientStateManager : INotifyPropertyChanged
{
    #region Private Variables
    private bool isForceToTop;
    private bool isClientEnabled;
    #endregion

    #region Public Properties
    public bool IsForceToTop
    {
        get { return isForceToTop; }
        set
        {
            isForceToTop = value;
            NotifyPropertyChanged();
        }
    }
    public bool IsClientEnabled
    {
        get { return isClientEnabled; }
        set
        {
            isClientEnabled = value;
            NotifyPropertyChanged();
        }
    }       
    #endregion

    #region Private Methods
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion

    #region Public Methods
    public void Lock() => this.IsClientEnabled = false;
    public void UnLock() => this.IsClientEnabled = true;
    public void SetTop() => this.IsForceToTop = true;
    public void UnSetTop() => this.IsForceToTop = false;
    #endregion

    #region Public Events
    public event PropertyChangedEventHandler PropertyChanged; 
    #endregion
}

Step 2.1: Added my state manager class to my ViewModel. (MVVM)

  internal class MainWindowViewModel : INotifyPropertyChanged
  {
    #region Constructor
    public MainWindowViewModel() 
    {
        ClientStateManager = new ClientStateManager();
    }
    #endregion

    #region Public Properties  
    public ClientStateManager ClientStateManager { get; private set; }
    #endregion
  }

Step 2.2: Then set your window data context to your view model.

  private MainWindowViewModel model;
  private MainWindow()
  {
        InitializeComponent();
        this.model = new MainWindowViewModel();
        this.DataContext = model;
  }   

Step 3: Add your data binding to your window.

  <Window x:Class="Intouch_Work.MainWindow"
    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"
    xmlns:ojects="clr-namespace:Framework.Object;assembly=Framework"
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"     
    mc:Ignorable="d"
    Title="Intouch" Height="800" Width="1100"
    x:Name="mainWindow"
    Topmost="{Binding Path=ClientStateManager.IsForceToTop, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">

So now you can manage your window state using the state manager object initialized within the View Model. You can call SetTop() from you state manager to push it forward, or UnSetTop() to stop it. Hope this helps anyone looking to do the same.



回答5:

I had a main window that I wanted to keep on top of everything (if the user checked "always on top".
This worked for me. Hope this helps someone.

        // If we want main to stay on top, we set the rest of the menus to Not be top 
        if (mnuViewMainWindowAlwaysOnTopo.IsChecked)
        {
            this.Topmost = true;
            foreach (Window window in Application.Current.Windows)
            {
                // Don't change for main window
                if (window.GetType().Name != this.GetType().Name)
                {
                    window.Topmost = false;
                }
            }
        }
        else
        {
            this.Topmost = false;
        }


回答6:

None of the solutions above for me worked, so here is what I ended up doing. It worked perfectly for me.

Basically, to keep it on top you just set the lose focus event to make it go back to top.

XAML:

PreviewLostKeyboardFocus="Window_PreviewLostKeyboardFocus"

Code Behind:

private void Window_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
     {
          Window window = (Window)sender;
          window.Topmost = true;
     }


标签: c# wpf topmost