一个有点老的问题,但我刚刚遇到了同样的问题,找不到答案,所以这就是我想出的。
所以问题是控件及其装饰器重叠并且将装饰器设置为可见会触发装饰控件上的 MouseLeave,因为它现在被装饰器覆盖。
解决方案是对装饰控件及其装饰器上的每个 MouseEnter 和 MouseLeave 做出反应,并手动进行命中测试。如果它们中的任何一个被击中,那么装饰器应该是可见的,否则会折叠。
因此,您需要能够从装饰控件中获取装饰器,反之亦然。从装饰器获取装饰控件没有问题(使用 AdornedElement 属性),但框架(AFAIK)不提供控件的装饰器,因此我使用字典将我的控件映射到其装饰器列表。
这是我的 Panel 派生类中的代码(包含并排列我的控件及其装饰器):
private readonly Dictionary<Control, List<Adorner>> _controlToAdornersMap;
...
private void CreateMyControl()
{
var control = new MyControl();
control.MouseEnter += OnMyControlMouseEnterOrLeave;
control.MouseLeave += OnMyControlMouseEnterOrLeave;
Children.Add(control);
AddAdorners(control);
}
private void AddAdorners(Control control)
{
var myAdorner = new MyAdorner(control);
myAdorner.MouseEnter += OnMyAdornerMouseEnterOrLeave;
myAdorner.MouseLeave += OnMyAdornerMouseEnterOrLeave;
var adornerLayer = AdornerLayer.GetAdornerLayer(control);
adornerLayer.Add(myAdorner);
_controlToAdornersMap[control] = new List<Adorner> {myAdorner};
}
private void OnMyControlMouseEnterOrLeave(object sender, MouseEventArgs e)
{
HitTestAndSetAdornersVisibility((MyControl)sender, e);
}
private void OnMyAdornerMouseEnterOrLeave(object sender, MouseEventArgs e)
{
var adorner = (Adorner)sender;
HitTestAndSetAdornersVisibility((MyControl)adorner.AdornedElement, e);
}
private void HitTestAndSetAdornersVisibility(MyControl control, MouseEventArgs e)
{
var adorners = _controlToAdornersMap[control];
var hitTestSubjects = new List<UIElement> { control }.Concat(adorners);
var hit = hitTestSubjects.Any(i => VisualTreeHelper.HitTest(i, e.GetPosition(i)) != null);
SetAdornersVisibility(adorners, hit ? Visibility.Visible : Visibility.Collapsed);
}
private static void SetAdornersVisibility(IEnumerable<Adorner> adorners, Visibility visibility)
{
if (adorners != null)
foreach (var adorner in adorners)
adorner.Visibility = visibility;
}