Пользовательский заголовок при использовании нескольких мониторов. Определение абсолютных координат курсора мыши
Суть проблемы : у WPF окна кастомный header вместо стандартного.
<Window ...
WindowStyle="None"/>
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid MouseLeftButtonDown="DragMove_MouseLeftButtonDown"
x:Name="HeaderGrid">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<TextBlock></TextBlock>
<Button x:Name="btnMinimize" Content="?" Style="{StaticResource HeaderButton}"
Click="btnMinimize_Click"
/>
<Button x:Name="btnMaximize" Content="?" Style="{StaticResource HeaderButton}"
Click="btnMaximize_Click"
/>
<Button x:Name="btnClose" Content="❌" Style="{StaticResource HeaderButton}"
FontWeight="Light"
FontSize="16"
Click="btnClose_Click"
Margin="0 0 5 0"
/>
</StackPanel>
</Grid>
Нужно воспроизвести поведение стандартного заголовка окна. То есть, что бы можно было за него перетаскивать, а так же, в случае, когда окно развёрнуто, то нажав на него, оно возвращается к обычному размеру и позиционируется под курсором мышки. С одним монитором всё работает отлично
private void DragMove_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (WindowState == WindowState.Maximized)
{
WindowState = WindowState.Normal;
System.Windows.Point mousePosition = Mouse.GetPosition(this);
Top = mousePosition.Y;
Left = mousePosition.X - (Width / 2) + (1920 * GetCurrentScreenNumber());
}
DragMove();
}
public int GetCurrentScreenNumber()
{
System.Drawing.Point cursorPosition = System.Windows.Forms.Control.MousePosition;
Screen screen = Screen.FromPoint(cursorPosition);
return Array.IndexOf(Screen.AllScreens, screen);
}
С двумя всё уже гораздо сложнее с таким подходом. Пока смог реализовать относительно корректную работу двух дисплеев в случае, когда основной находится слева.
Но что если экранов 3 или больше? Есть ли какой-то вариант определять координаты курсора не в относительных текущего экрана координатах, а в абсолютных? Ведь приведённый пример вполне себе работает, а значит есть какая-то абсолютная сетка экранных координат? Как-то можно получать координаты с неё? Или есть какие-то ещё пути решения данной проблемы?
П.С.: в WPF, я так понимаю своих механизмов получить координаты мыши нет и их приходится тащить из Winforms?
Ответы (1 шт):
Благодаря подсказкам @EvgeniyZ удалось реализовать нужное поведение с использованием класса WindowChrome. Для возможности клика по кнопкам в заголовке, используется свойство кнопок WindowChrome.IsHitTestVisibleInChrome="True" Работает с любым количеством и расположением мониторов. Позволяет создавать полностью настроенный под себя заголовок, например для ночной темы.
<Window x:Class="TestProject.View.TestWindow"
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"
mc:Ignorable="d"
WindowStyle="None" AllowsTransparency="True"
Background="Transparent"
Height="450" Width="800">
<WindowChrome.WindowChrome>
<WindowChrome ResizeBorderThickness="7"/>
</WindowChrome.WindowChrome>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="?"
WindowChrome.IsHitTestVisibleInChrome="True"
Click="btnMinimize_Click"
/>
<Button Content="?"
WindowChrome.IsHitTestVisibleInChrome="True"
Click="btnMaximize_Click"
/>
<Button Content="❌"
WindowChrome.IsHitTestVisibleInChrome="True"
FontWeight="Light"
FontSize="16"
Click="btnClose_Click"
Margin="0 0 5 0"
/>
</StackPanel>
</Grid>
</Window>
Код методов кнопок заголовка :
private void btnClose_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void btnMaximize_Click(object sender, RoutedEventArgs e)
{
if (WindowState == WindowState.Maximized)
{
WindowState = WindowState.Normal;
}
else
{
WindowState = WindowState.Maximized;
}
}
private void btnMinimize_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}