Первое решение
Если ваши элементы заполняют весь ваш ItemsPresenter, вы можете легко сделать это в чистом XAML.
Скопировать стандартный шаблон для ListBox и добавить границувокруг ItemsPresenter, который будет вычислять глубину тени для всех непокрытых предметов:
<Border custom:AppletButton.ShadowDepth="15">
<ItemsPresenter />
</Border>
Теперь добавьте триггер к границе, чтобы изменить это, когда IsMouseOver = "true":
<Border.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="custom:AppletButton.ShadowDepth" Value="10" />
</Trigger>
</Border.Triggers>
В вашем ItemTemplate, используйте FindAncestor, чтобы связать ShadowDepth с ShadowDepth границы:
ShadowDepth="{Binding Path=custom:AppletButton.ShadowDepth, RelativeSource={RelativeSource FindAncestor,Border,1}}"
Обратите внимание, что "Path =" требуется при использовании вложенных свойств.
Также в вашем ItemTemplate переопределитепараметр FindAncestor всякий раз, когда мышь находится над элементом:
<custom:AppletButton.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="ShadowDepth" Value="40" />
</Trigger>
</custom:AppletButton.Triggers>
Теперь каждый раз, когда мышь находится над панелью WrapPanel, все элементы будут иметь меньшую глубину тени, но если мышь находится над данным элементом, она будетимеют большую глубину тени.
Недостатком этого является то, что если мышь находится над пустой частью WrapPanel, все элементы будут уменьшать глубину тени, но ни одинбудет подсвечен.
Второе решение
Если вам нужно «отменить подсветку» элементов в списке только , когда мышь находится надфактический элемент (в отличие от панели), вам потребуется использовать некоторый код.
Один простой способ сделать это - создать свойство IsMouseOverAnyItem и использовать его, как показано выше.Например, вы можете создать подкласс WrapPanel и в MeasureOverride создать список объектов, которые привязываются к свойствам «IsMouseOver» каждого дочернего элемента панели, примерно так:
public class MyWrapPanel : WrapPanel
{
List<ValueMonitor> _monitors;
public bool IsMouseOverAnyItem { get { return (bool)GetValue(IsMouseOverAnyItemProperty); } set { SetValue(IsMouseOverAnyItemProperty, value); } }
public static readonly DependencyProperty IsMouseOverAnyItemProperty = DependencyProperty.Register("IsMouseOverAnyItem", typeof(bool), typeof(MyWrapPanel));
protected override Size MeasureOverride(Size constraint)
{
if(_monitors!=null) _monitors.ForEach(monitor => monitor.Disable());
_monitors = (
from child in Children.OfType<object>()
select new ValueMonitor(new Binding("IsMouseOver") { Source=child },
() => Update()) // ValueChangedAction
).ToList();
Update();
return base.MeasureOverride(constraint);
}
public void Update()
{
IsMouseOverAnyItem = _monitors.All(monitor => (bool)monitor.Value);
}
}
В приведенном выше примере предполагается, что у вас есть класс ValueMonitorкоторый может наблюдать значение привязки и уведомлять вас, если оно изменяется.Это может быть реализовано примерно так:
public class ValueMonitor : DependencyObject
{
Action _valueChangedAction;
public object Value { get { return (object)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } }
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(object), typeof(ValueMonitor), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) => ((ValueMonitor)obj)._valueChangedAction()
});
public ValueMonitor(BindingBase binding, Action valueChangedAction)
{
_valueChangedAction = valueChangedAction;
BindingOperations.SetBinding(this, ValueProperty, binding);
}
public void Disable()
{
ClearValue(ValueProperty);
}
}