本文经原作者授权以原创方式二次分享,欢迎转载、分享。 原文作者:唐宋元明清 原文地址:https://www.cnblogs.com/kybs0/p/7420767.html
解决:
1)单实例窗口,窗口每次隐藏后再显示时,位置居中显示
2)多屏幕下单实例窗口,当父窗口移动到其它屏幕时,单实例窗口再次弹出时,位置才更新到父窗口屏幕。
3)子窗口每次唤醒时,都居中显示。
Windows
的启动时位置显示,WindowStartupLocation
CenterOwner
--显示在父窗口的中间(设置Owner
)CenterScreen
--显示在当前屏幕中间Manual
--默认位置 当第一次Window.ShowDialog
时,window
显示如上设置。变更触发机制 上面只涉及到了首次显示位置,之后,窗口的位置会继续保留
如何设置窗口隐藏之后再次弹出时,显示在中间(CenterOwner/CenterScreen
)?如何设置窗口一直停留在显示在中间?
Hide(
)时,IsVisibile=false
.窗口再次ShowDialog
时,IsVisibile=true
;利用如上俩种机制,下面就可以搞事情了。
首先定义几个枚举:
/// <summary>
/// 窗口显示变更触发时机
/// </summary>
public enum WindowLocationInvokeOccasion
{
/// <summary>
/// 只要Activated就显示在中间
/// </summary>
Activated = 0,
/// <summary>
/// 只在第一次Activated时,显示在中间一次,之后的变化就不修改
/// </summary>
FirstActivated,
/// <summary>
/// 窗口每次显示时,窗口居中
/// <para>可以解决单实例窗口弹出不居中问题</para>
/// </summary>
Visibile,
/// <summary>
/// 窗口每次显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中
/// <para>可以解决单实例窗口弹出不居中问题</para>
/// </summary>
VisibileInDifferentScreen,
/// <summary>
/// 不触发
/// </summary>
Defatult
}
如上枚举包含了4种触发机制。
我们再定义个附加属性,通过附加属性去设置窗口的额外功能-居中显示触发机制
/// <summary>
/// 窗口显示居中触发时机
/// <para>另:居中显示设置,请使用<see cref="Window"/>的<see cref="WindowStartupLocation"/>属性</para>
/// </summary>
public static readonly DependencyProperty InvokeOccasionProperty = DependencyProperty.RegisterAttached(
"InvokeOccasion", typeof(WindowLocationInvokeOccasion), typeof(WindowLocationOptions),
new PropertyMetadata(default(WindowLocationInvokeOccasion), InvokeOccasionProperty_ChangedCallback));
在属性更改触发事件中,根据不同的触发条件,设置不同的居中显示。
Activated
--只要Activated
就显示在中间 每次触发,直接显示窗口即可;Activated
通过设置Window.Activated -= ShowInCenter_Activated
;禁用下次触发进入Visibile
VisibileInDifferentScreen
窗口显示时,如父窗口与当前窗口不在同一屏幕时,窗口居中. 怎么判断当前子窗口与父窗口是否在同一屏幕?var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
double dpiXRatio = currentGraphics.DpiX / 96;
double dpiYRatio = currentGraphics.DpiY / 96;
//当子窗口与父窗口所在屏幕相同时,不作处理
var isSubWindowInSameScreen = subWindow.Left > screen.Bounds.Left / dpiXRatio &&
subWindow.Left < screen.Bounds.Left / dpiXRatio + screen.Bounds.Width / dpiXRatio &&
subWindow.Top > screen.Bounds.Top / dpiYRatio &&
subWindow.Top < screen.Bounds.Top / dpiYRatio + screen.Bounds.Height / dpiYRatio;
return isSubWindowInSameScreen;
介绍完成触发条件,下面说下窗口居中显示。
居中显示,分为当前屏幕内居中/主窗口内居中,直接上代码。
1)在主窗口中居中显示-CenterOwner 设置窗口的依靠位置Location(Left,Top)(左上角)
WindowState=“Maximized”
最大化窗口,固定的弹出到主屏幕,因此需额外处理,根据屏幕Location
设置位置;location
,因窗口设置margin
,有可能不准确,故取屏幕位置Left/Top
可能为负/// <summary>
/// 在主窗口中居中显示
/// </summary>
/// <param name="subWindow"></param>
/// <param name="parentWindow"></param>
private static void SetWindowInCenterOwner(Window subWindow, Window parentWindow)
{
//最大化窗口,固定的弹出到主屏幕,因此需额外处理
if (subWindow.WindowState == WindowState.Maximized)
{
//子窗口最大化时,需要根据屏幕设置位置;
var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
double dpiXRatio = currentGraphics.DpiX / 96;
double dpiYRatio = currentGraphics.DpiY / 96;
subWindow.Left = screen.Bounds.Left / dpiXRatio;
subWindow.Top = screen.Bounds.Top / dpiYRatio;
}
if (parentWindow.WindowState == WindowState.Maximized)
{
//父窗口最大化时,父窗口的location,因窗口设置margin,有可能不准确,故取屏幕位置
var screen = Screen.FromHandle(new WindowInteropHelper(parentWindow).Handle);
Graphics currentGraphics = Graphics.FromHwnd(new WindowInteropHelper(parentWindow).Handle);
double dpiXRatio = currentGraphics.DpiX / 96;
double dpiYRatio = currentGraphics.DpiY / 96;
//窗口居中显示
subWindow.Left = screen.Bounds.Left / dpiXRatio +
(screen.Bounds.Width / dpiXRatio - subWindow.ActualWidth) / 2;
subWindow.Top = screen.Bounds.Top / dpiYRatio +
(screen.Bounds.Height / dpiYRatio - subWindow.ActualHeight) / 2;
}
else
{
//窗口居中显示
subWindow.Left = parentWindow.Left + (parentWindow.ActualWidth - subWindow.ActualWidth) / 2;
subWindow.Top = parentWindow.Top + (parentWindow.ActualHeight - subWindow.ActualHeight) / 2;
}
}
2)当前屏幕内居中-CenterScreen
;
DPI
。win
的显示设置,调整文本显示比例,屏幕的位置转换(X,Y)``,得考虑
DPI`的换算;/// <summary>
/// 在父窗口所在屏幕居中显示
/// </summary>
/// <param name="subWindow"></param>
/// <param name="parentWindow"></param>
private static void SetWindowInCenterScreen(Window subWindow, Window parentWindow)
{
SetWindowLocationInScreen(subWindow, parentWindow, subWindow.WindowState);
}
private const int DpiPercent = 96;
private static void SetWindowLocationInScreen(Window subWindow, Window parentWindow, WindowState windowState)
{
var intPtr = new WindowInteropHelper(parentWindow).Handle;
var screen = Screen.FromHandle(intPtr);
using (Graphics currentGraphics = Graphics.FromHwnd(intPtr))
{
double dpiXRatio = currentGraphics.DpiX / DpiPercent;
double dpiYRatio = currentGraphics.DpiY / DpiPercent;
if (windowState == WindowState.Maximized)
{
//设置全屏Location
subWindow.Left = screen.Bounds.Left / dpiXRatio;
subWindow.Top = screen.Bounds.Top / dpiYRatio;
}
else
{
//设置居中Location
subWindow.Left = screen.Bounds.Left / dpiXRatio +
(screen.Bounds.Width / dpiXRatio - subWindow.ActualWidth) / 2;
subWindow.Top = screen.Bounds.Top / dpiYRatio +
(screen.Bounds.Height / dpiYRatio - subWindow.ActualHeight) / 2;
}
}
}