WPF - 通过xaml进行不同控件的动画

时间:2010-11-10 16:48:44

标签: wpf animation

我有一个填充了自定义控件的列表框。它工作正常。现在我想创造这种效果......

当用户将鼠标悬停在列表框中的某个项目上时,我希望该项目增加其shadowdepth(已显示)和所有其他项目以减少其shadowdepth。可以这样做吗?可以在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 :(得分:0)

第一个解决方案

如果您的商品填满整个ItemsPresenter,您可以在纯XAML中轻松完成。

复制ListBox的标准模板,并在ItemsPresenter周围添加一个Border,它将计算所有非悬停项目的阴影深度:

<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绑定到Border的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的空白部分上,则所有项目都会降低其阴影深度,但不会有任何高度。

第二个解决方案

如果当鼠标悬停在实际项目上(而非在面板上方)时,如果您需要在列表框 hilight“项目 ,则需要使用一些代码。< / p>

执行此操作的一种简单方法是创建“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);
  }
}