WPF всегда на вершине
Можно ли сделать так, чтобы окно всегда оставалось сверху, даже когда другое приложение работает в полноэкранном режиме? Я сейчас пользуюсь TopMost = true
но когда другое приложение работает на полноэкранном, мое становится невидимым. Это WindowStyle = None
окно кстати.
Редактировать: И не позволяйте другим окнам минимизировать курс
7 ответов
Это не будет работать в 100% случаев, но несколько улучшит ситуацию. Вы можете установить Topmost = true
в обработчике для Window.Deactivated
событие:
private void Window_Deactivated(object sender, EventArgs e)
{
Window window = (Window)sender;
window.Topmost = true;
}
Deactivated
событие будет вызываться всякий раз, когда ваше приложение теряет фокус (часто, когда другое приложение запрашивает Topmost
) и поэтому после этого ваше приложение будет сброшено.
Try this solution from MSDN, it should work for you. в Window Activated Event
добавьте следующий код:
this.Width = System.Windows.SystemParameters.PrimaryScreenWidth;
this.Height = System.Windows.SystemParameters.PrimaryScreenHeight;
this.Topmost = true;
this.Top = 0;
this.Left=0;
в DeActivated Event
add the following code
this.Topmost = true;
this.Activate();
Ни одно из вышеперечисленных решений для меня не сработало, так что вот что я и сделал Это отлично сработало для меня.
По сути, чтобы держать его на вершине, просто установите событие потери фокуса, чтобы оно вернулось наверх.
XAML:
PreviewLostKeyboardFocus="Window_PreviewLostKeyboardFocus"
Код позади:
private void Window_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
Window window = (Window)sender;
window.Topmost = true;
}
Если вы хотите, чтобы ваше приложение оставалось поверх ВСЕГО (включая интерфейс запуска в Windows 8, ранее известный как "Метро"), то вы можете указать UiAccess="True" в файле манифеста. Это обычно используется приложениями специальных возможностей, такими как экранные клавиатуры.
По памяти нужно сделать 3 вещи;
- Request UiAccess="True"
- Подпишите исполняемый файл вашего приложения с признанным сертификатом. Я получил бесплатный сертификат подписи кода от Certum, так как мой проект с открытым исходным кодом.
- Установите ваше приложение в "Надежное расположение", которое в моем случае было каталогом программных файлов. Официального определения "Надежного местоположения" я бы не нашел.
Так что я недавно столкнулся с тем же требованием. Кажется, что лучший ответ, как и второй, не помог мне. Я нашел решение, которое, кажется, работает безупречно и в некоторой степени придерживается наилучшей практики использования MVVM.
Использование ниже заставляет окно к вершине и никогда не теряет изменения, как другие решения.
Шаг 1: Я создал простой класс диспетчера состояний для моего главного окна клиента. Я использовал INotifyPropertyChanged для синхронизации свойств при использовании прямой привязки к моему окну. (очень важно)
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
}
Шаг 2.1: Добавлен мой класс менеджера состояний в мою ViewModel. (MVVM)
internal class MainWindowViewModel : INotifyPropertyChanged
{
#region Constructor
public MainWindowViewModel()
{
ClientStateManager = new ClientStateManager();
}
#endregion
#region Public Properties
public ClientStateManager ClientStateManager { get; private set; }
#endregion
}
Шаг 2.2: Затем установите контекст данных вашего окна в соответствии с моделью представления.
private MainWindowViewModel model;
private MainWindow()
{
InitializeComponent();
this.model = new MainWindowViewModel();
this.DataContext = model;
}
Шаг 3: Добавьте привязку данных к вашему окну.
<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}">
Теперь вы можете управлять состоянием окна, используя объект диспетчера состояний, инициализированный в модели представления. Вы можете вызвать SetTop() из вашего менеджера состояний, чтобы продвинуть его вперед, или UnSetTop(), чтобы остановить его. Надеюсь, это поможет любому, кто хочет сделать то же самое.
Мне нужно было что-то подобное для промышленного приложения контроля качества, где операторы, не являющиеся администраторами, не должны иметь возможность сворачивать или использовать что-либо еще на выделенном компьютере во время работы приложения, даже
Windows+D
чтобы открыть рабочий стол. И я обнаружил, что самый чистый и простой способ добиться этого - это:
- Настройки правильные
Width
,Height
,WindowStyle
,WindowState
иTopmost
характеристики. - Обработка некоторых связанных событий:
StateChanged
,Deactivated
,LostFocuse
,LostMouseCapture
,LostKeyboardFocus
иPreviewLostKeyboardFocus
. - Обработка событий закрытия с помощью
ALT+F4
или настраиваемая кнопка).
Нет необходимости в P / Invoke, вот полный код:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
Closing += OnClosing;
StateChanged += OnStateChanged;
Deactivated += (sender, args) => Activate();
LostFocus += (sender, args) => Focus();
LostMouseCapture += (sender, args) => Mouse.Capture(this);
LostKeyboardFocus += (sender, args) => Keyboard.Focus(this);
PreviewLostKeyboardFocus += (sender, args) => Keyboard.Focus(this);
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
Width = SystemParameters.PrimaryScreenWidth;
Height = SystemParameters.PrimaryScreenHeight;
WindowStyle = WindowStyle.None;
WindowState = WindowState.Maximized;
Topmost = true;
// Other stuff here
}
private void OnClosing(object sender, CancelEventArgs e)
{
// You might want to allow only some users to close the app
if (MessageBox.Show("Are you an admin?", "Admin Check", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.No)
e.Cancel = true;
}
private void OnStateChanged(object sender, EventArgs e)
{
if (WindowState == WindowState.Minimized)
WindowState = WindowState.Maximized;
}
}
Вы также можете поместить часть этого в XAML:
<Window x:Class="FullScreen.MainWindow"
...
Title="MainWindow"
WindowState="Maximized"
WindowStyle="None"
Topmost="True">
<Grid>
</Grid>
</Window>
У меня было главное окно, которое я хотел держать поверх всего (если пользователь выбрал "всегда сверху").
Это сработало для меня. Надеюсь, это кому-нибудь поможет.
// 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;
}