使用Popup初衷是什么?
>>> 悬浮效果,可以透过Pop弹窗,继续操作窗口背后的动作。像导航
原始Popup控件,设置 [PlacementTarget] 目标控件,就相对于该控件弹出,类似菜单栏效果。
但是,不是很好用,比如想要屏幕下方、居中弹出;大多数想要点击展开、再点击关闭,而不是点击Popup外区域就折叠。另外,Popup是相对于屏幕的,相当于屏幕的TopMost,屏幕尺寸改变、拖动,Popup不会跟随移动。
来自定义吧,想做什么都想办法实现~
1.定义PopupEx.cs 控件类 【复制可用】【挺全】
需要什么属性自己加。一开始代码也没有这么长,需求越来越多就...
👇简单解析下:
① 相对InWindow通知位置跟随,同时,UnRegisterPopupEvent(); 由于绑定了InWindow的位置、尺寸更新事件,所以避免资源占用,在InWindow释放前需要 -= 释放Popup注册的InWindow事件。
② 相对InPage调整具体位置,尺寸按比例缩放之类的。
③ OnOpened();
UpdateWindow(); 有时候Pop_A弹出再弹出Pop_B,会改变A的层级,先调整位于软件的上一层(非TopMost),否则可能点击会跑到某个控件后面。
SetPopupScreenControl(); 另外,有的过Height的Pop,第一次弹出超过PC屏幕的75%会导致显示截断,所以需要调整具体Pop尺寸,SetPopupScreenControl();
PositionChanged(null, null); 然后是刷新位置 PositionChanged(); 之前Pop关闭后窗口调整过分辨率等导致尺寸/位置变化
④ Pop_PreviewMouseDown(); 如果Pop失去过焦点,内的控件聚焦,但Pop不一定聚焦,导致Pop内的文本输入框IME输入法不会和光标跟随、焦点触发事件无效。必须要显示调用Windows的方法(HwndSource)聚焦(SetFocus不一定有用)。
public class PopupEx : Popup
{
/// <summary>
/// 静态构造方法
/// </summary>
static PopupEx()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(PopupEx), new FrameworkPropertyMetadata(typeof(PopupEx)));
}
/// <summary>
/// 构造方法
/// </summary>
public PopupEx()
{
this.Loaded += Pop_Loaded;
this.PreviewMouseDown += Pop_PreviewMouseDown;
}
#region Property 属性
public static readonly DependencyProperty IsPositionUpdateProperty = DependencyProperty.Register("IsPositionUpdate", typeof(bool), typeof(PopupEx), new PropertyMetadata(true, new PropertyChangedCallback(IsPositionUpdateChanged)));
public static readonly DependencyProperty TopmostProperty = Window.TopmostProperty.AddOwner(typeof(Popup), new FrameworkPropertyMetadata(false, OnTopmostChanged));
public static readonly DependencyProperty PopLevelProperty = DependencyProperty.Register("PopLevel", typeof(int), typeof(PopupEx), new PropertyMetadata(-2));
public static readonly DependencyProperty InPageProperty = DependencyProperty.Register("InPage", typeof(FrameworkElement), typeof(PopupEx));
/// <summary>
/// 是否窗口随动,默认为随动(true)
/// </summary>
public bool IsPositionUpdate
{
get { return (bool)GetValue(IsPositionUpdateProperty); }
set { SetValue(IsPositionUpdateProperty, value); }
}
/// <summary>
/// 层级 Topmost
/// </summary>
public bool Topmost
{
get { return (bool)GetValue(TopmostProperty); }
set { SetValue(TopmostProperty, value); }
}
/// <summary>
/// Popup所属Window
/// </summary>
private Window InWindow { get; set; }
/// <summary>
/// Popup所在页面/窗口
/// 计算Popup的偏移位置
/// </summary>
public FrameworkElement InPage
{
get { return (FrameworkElement)GetValue(InPageProperty); }
set { SetValue(InPageProperty, value); }
}
#endregion
#region EventHandler 事件
/// <summary>
/// 随动 属性变更
/// </summary>
/// <param name="d"></param