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.
Topmost="True"
is also very useful in debugging with visual studio. – Topi