简化示例; 图片由两个元素A和B组成的维恩图,它们重叠。 如果我鼠标悬停(A AND(不是B))A全部亮起。 如果我鼠标悬停(B AND(不是A))所有B都亮起来。 如果我鼠标悬停(A和B),两者应该亮起来。只有最顶部标记为鼠标悬停在它上面。
有没有办法让IsMouseOver像这样隧道? 如果没有,有什么建议吗?
答案 0 :(得分:3)
您可以使用VisualTreeHelper进行手动命中测试。这可以进入某个父对象的MouseMove处理程序。这里我假设一个由名为RedCircle和BlueCircle的椭圆组成的维恩图:
bool overRed = false;
bool overBlue = false;
if (BlueCircle.IsMouseOver || RedCircle.IsMouseOver)
{
HitTestParameters parameters = new PointHitTestParameters(e.GetPosition(RedCircle));
VisualTreeHelper.HitTest(RedCircle, new HitTestFilterCallback(element => HitTestFilterBehavior.Continue), result =>
{
if (result.VisualHit == RedCircle)
overRed = true;
return HitTestResultBehavior.Continue;
}, parameters);
parameters = new PointHitTestParameters(e.GetPosition(BlueCircle));
VisualTreeHelper.HitTest(BlueCircle, new HitTestFilterCallback(element => HitTestFilterBehavior.Continue), result =>
{
if (result.VisualHit == BlueCircle)
overBlue = true;
return HitTestResultBehavior.Continue;
}, parameters);
}
答案 1 :(得分:0)
使用IsMouseDirectlyOver属性。这似乎是你需要的东西。
http://msdn.microsoft.com/en-us/library/system.windows.uielement.ismousedirectlyoverproperty.aspx
答案 2 :(得分:0)
我需要在我的项目中使用类似的东西,并提供快速解决方案。
public sealed class IsMouseOverEnchancementBehavior
{
#region MouseCurrentPosition
internal sealed class MouseCurrentPosition
{
private Point _currentPosition;
private readonly Timer _timer = new Timer(250);
public event EventHandler<EventArgs> PositionChanged;
public MouseCurrentPosition()
{
_timer.Elapsed += timer_Elapsed;
_timer.Start();
}
public Point CurrentPosition
{
get { return _currentPosition; }
set
{
if (_currentPosition != value)
{
_currentPosition = value;
var pos = PositionChanged;
if (pos != null)
PositionChanged(null, null);
}
}
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetCursorPos(ref NativePoint pt);
public static Point GetCurrentMousePosition()
{
var nativePoint = new NativePoint();
GetCursorPos(ref nativePoint);
return new Point(nativePoint.X, nativePoint.Y);
}
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Point current = GetCurrentMousePosition();
CurrentPosition = current;
}
[StructLayout(LayoutKind.Sequential)]
internal struct NativePoint
{
public int X;
public int Y;
};
}
#endregion
private static readonly MouseCurrentPosition _mouseCurrentPosition = new MouseCurrentPosition();
public static DependencyProperty IsMouseOverIgnoreChild =
DependencyProperty.RegisterAttached("IsMouseOverIgnoreChild", typeof (bool),
typeof (IsMouseOverEnchancementBehavior),
new FrameworkPropertyMetadata(false));
public static readonly DependencyProperty IsMouseOverEnchancementEnabled =
DependencyProperty.RegisterAttached("IsMouseOverEnchancementEnabled",
typeof (bool), typeof (IsMouseOverEnchancementBehavior),
new UIPropertyMetadata(false, OnMouseOverEnchancementEnabled));
private static void OnMouseOverEnchancementEnabled(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// todo: unhook if necessary.
var frameworkElement = (FrameworkElement) d;
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(UIElement.IsMouseOverProperty,
typeof (UIElement));
Action calculateCurrentStateAction = () =>
{
// cheap check.
if (frameworkElement.IsMouseOver)
{
SetIsMouseOverIgnoreChild(frameworkElement, true);
return;
}
// through hit-testing.
var isMouseOver = VisualTreeHelper.
HitTest(frameworkElement, Mouse.GetPosition(frameworkElement)) != null;
SetIsMouseOverIgnoreChild(frameworkElement, isMouseOver);
};
// if the mose moves,
// we shall re-do hit testing.
_mouseCurrentPosition.PositionChanged += delegate
{
frameworkElement.Dispatcher.Invoke(
calculateCurrentStateAction);
};
// If IsMouseOver changes,
// we can propagate it to our property.
dpd.AddValueChanged(frameworkElement,
delegate { calculateCurrentStateAction(); });
}
#region Misc
public static bool GetIsMouseOverEnchancementEnabled(DependencyObject obj)
{
return (bool) obj.GetValue(IsMouseOverEnchancementEnabled);
}
public static void SetIsMouseOverEnchancementEnabled(DependencyObject obj, bool value)
{
obj.SetValue(IsMouseOverEnchancementEnabled, value);
}
public static bool GetIsMouseOverIgnoreChild(DependencyObject obj)
{
return (bool) obj.GetValue(IsMouseOverIgnoreChild);
}
public static void SetIsMouseOverIgnoreChild(DependencyObject obj, bool value)
{
obj.SetValue(IsMouseOverIgnoreChild, value);
}
#endregion
}
它更像是使用计时器的通用解决方案。
这就是我在风格中使用它的方式:
<Setter Property="behaviors:IsMouseOverEnchancementBehavior.
IsMouseOverEnchancementEnabled" Value="True" />
<Style.Triggers>
<!-- Just a visual feedback -->
<!-- Let the user know that mouse is over the element -->
<!-- When we are in editmode -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInEditMode" Value="True" />
<Condition Property="behaviors:IsMouseOverEnchancementBehavior.IsMouseOverIgnoreChild" Value="True" />
</MultiTrigger.Conditions>
...do stuff here....