WPF - анимация для разных элементов управления через xaml - PullRequest
1 голос
/ 10 ноября 2010

У меня есть список, заполненный пользовательским элементом управления.Работает нормально.Теперь я пытаюсь создать этот эффект ...

Когда пользователь наводит курсор на элемент в списке, я хочу, чтобы этот элемент увеличил свою глубину тени (уже отображается), а все остальные элементы уменьшили свою глубину тени.Можно ли это сделать?Можно ли это сделать в Xaml?

Я играл с ним, но безуспешно.

Вот мои текущие настройки списка, если это имеет значение ...

<ListBox ItemsSource="{Binding Path=Applets}" Margin="10,92,10,10" ScrollViewer.HorizontalScrollBarVisibility="Disabled" >

        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Orientation="Horizontal" IsItemsHost="True"  />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>

        <ListBox.ItemTemplate>
            <DataTemplate>
                <custom:AppletButton 
                    Margin="{Binding Path=DesiredMargin}" 
                    Width="{Binding Path=DesiredWidth}" 
                    Height="{Binding Path=DesiredHeight}"

                    CornerRadius="{Binding Path=CornerRoundness}"
                    BackgroundImage="{Binding Path=BackImage}"
                    BorderThickness="{Binding Path=BorderWidth}"

                    Text ="{Binding Path=Title}"
                    TextColor ="{Binding Path=TitleColor}"
                    AlternateText ="{Binding Path=Description}"
                    AlternateTextColor ="{Binding Path=DescriptionColor}"
                    AlternateTextShadowColor="White"
                    AlternateTextSize="56"
                    TextShadowColor="Gray"
                    CaptionTextSize="72"
                    ToolTip="{Binding Path=ToolTip}"
                    ShadowDepth="15"
                    SaturationLevel="{Binding Path=Saturation}"

                    Tag="{Binding Path=Tag}">


                    <custom:AppletButton.BorderBrush>
                        <ImageBrush ImageSource="{Binding BorderBrushImage}" />
                    </custom:AppletButton.BorderBrush>

                    <custom:AppletButton.BitmapEffect>
                        <DropShadowBitmapEffect x:Name="AppletShadow" ShadowDepth="5" Opacity="0.5" Softness="0.5" />
                    </custom:AppletButton.BitmapEffect>

                </custom:AppletButton>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

TIA

Джефф

1 Ответ

0 голосов
/ 10 ноября 2010

Первое решение

Если ваши элементы заполняют весь ваш 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);
  }
} 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...