将情节提要的目标设置为 DataTemplate WPF 中的按钮

Set Target of Storyboard to Button inside a DataTemplate WPF

我们正在尝试根据 window 大小设置按钮的高度和宽度。我们希望使用视觉状态来实现这一点。我们想将 Storyboard Target 设置为 DataTemplate 内的按钮。由于 DataTemplate 的名称范围,无法使用 StoryBoard.TargetName 按名称直接设置目标。在 XAML.

中有什么方法可以做到这一点

参考-

XAML:

<UserControl x:Class="ResizeSampleApp.Controls.ResizeUserControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ResizeSampleApp.Controls"
             mc:Ignorable="d" 
             SizeChanged="CurrentWindow_SizeChanged"
             x:Name="DashBoard"
             >


    <Grid x:Name="grid">
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup x:Name="ResizeStates">
                <VisualState x:Name="FirstHorizontalBreakpoint">
                    <Storyboard >
                        <DoubleAnimation To="116" Storyboard.TargetName="TargetBtn" Storyboard.TargetProperty="Height"></DoubleAnimation>
                        <DoubleAnimation To="182" Storyboard.TargetName="TargetBtn" Storyboard.TargetProperty="Width"></DoubleAnimation>
                    </Storyboard>
                </VisualState>
                <VisualState x:Name="MinSize">
                    <Storyboard>
                        <DoubleAnimation To="100" Storyboard.TargetName="TargetBtn" Storyboard.TargetProperty="Height"></DoubleAnimation>
                        <DoubleAnimation To="197" Storyboard.TargetName="TargetBtn" Storyboard.TargetProperty="Width"></DoubleAnimation>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>

        <StackPanel Orientation="Vertical">

            <Grid Margin="10">
                <ItemsControl Name="icTodoList">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Button x:Name="TargetBtn" Content="{Binding Title}" />
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Grid>
        </StackPanel>
    </Grid>
</UserControl>

C#:

public class TodoItem
    {
        public string Title { get; set; }
       
    }
    public partial class ResizeUserControl : UserControl
    {
        public ResizeUserControl()
        {
            InitializeComponent();

            List<TodoItem> items = new List<TodoItem>();
            items.Add(new TodoItem() { Title = "Testing 1 " });
            items.Add(new TodoItem() { Title = "Testing 2" });
            items.Add(new TodoItem() { Title = "Testing 3" });

            icTodoList.ItemsSource = items;


        }
        public void CurrentWindow_SizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
        {
            

            if (this.ActualWidth > 847)
            { 
                VisualStateManager.GoToState(this.DashBoard, "FirstHorizontalBreakpoint", false);
            }
            else
            {
                VisualStateManager.GoToState(this.DashBoard, "MinSize", false);
            }
        }
}

提前致谢。

无法使用视觉状态动画来为 DataTemplate 中的属性设置动画。 DataTemplate 只是一个模板,它不是可视化树的一部分,在 Storyboard 被定义的那一刻。将为每个模板化目标复制模板,例如每个项目容器。这意味着将有多个名称为 TargetBtn 的按钮 - 从模板范围外查看时。所以你必须将动画移动到 DataTemplate 范围,这意味着在模板内部。

除了控件的视觉状态定义之外,您还应该添加属性以将视觉状态反映为对象状态。
Microsoft Docs 建议对每个状态执行此操作是最佳做法:添加 IsMouseOver 等属性以指示 MouseOver 状态或 IsFocusedFocused 串联状态,仅举一些框架示例。
这允许您的控件将视觉状态表示为真实实例状态,可以在控件直接内容的上下文之外使用 - 视觉状态只能由 VisualStateManager.

使用

然后您可以使用这个通常 public 只读依赖属性来触发例如一个 DataTrigger,您在 DataTemplate 中定义它以动画模板的内容:

ResizeUserControl.xaml.cs

public partial class ResizeUserControl : UserControl
{
  #region IsExpandedViewEnabled read-only dependency property

  protected static readonly DependencyPropertyKey IsExpandedViewEnabledPropertyKey = DependencyProperty.RegisterReadOnly(
    "IsExpandedViewEnabled",
    typeof(bool),
    typeof(ResizeUserControl),
    new PropertyMetadata(default(bool)));

  public static readonly DependencyProperty IsExpandedViewEnabledProperty = MyControl.IsExpandedViewEnabledPropertyKey.DependencyProperty;

  public bool IsExpandedViewEnabled
  {
    get => (bool) GetValue(MyControl.IsExpandedViewEnabledProperty);
    private set => SetValue(MyControl.IsExpandedViewEnabledPropertyKey, value);
  }

  #endregion IsExpandedViewEnabled read-only dependency property

  public ResizeUserControl()
  {
    InitializeComponent();
  }

  #region Overrides of FrameworkElement

  protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
  {
    base.OnRenderSizeChanged(sizeInfo);
    if (this.ActualWidth > 847)
    {
      VisualStateManager.GoToState(this, "FirstHorizontalBreakpoint", false);
      this.IsExpandedViewEnabled = true;
    }
    else
    {
      VisualStateManager.GoToState(this, "MinSize", false);
      this.IsExpandedViewEnabled = false;
    }
  }
}

ResizeUserControl.xaml

<UserControl>
  <Grid x:Name="grid">
    <StackPanel Orientation="Vertical">
      <Grid Margin="10">
        <ItemsControl Name="icTodoList"
                      ItemsSource="{Binding DataItems}">
          <ItemsControl.ItemTemplate>
            <DataTemplate>
              <Button x:Name="TargetBtn" Height="60"
                      Content="{Binding Title}" />

              <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=IsExpandedViewEnabled}"
                             Value="True">
                  <DataTrigger.EnterActions>
                    <BeginStoryboard>
                      <Storyboard>
                        <DoubleAnimation To="116" Storyboard.TargetName="TargetBtn" Storyboard.TargetProperty="Height" />
                        <DoubleAnimation To="182" Storyboard.TargetName="TargetBtn" Storyboard.TargetProperty="Width" />
                      </Storyboard>
                    </BeginStoryboard>
                  </DataTrigger.EnterActions>

                  <DataTrigger.ExitActions>
                    <BeginStoryboard>
                      <Storyboard>
                        <DoubleAnimation To="100" Storyboard.TargetName="TargetBtn" Storyboard.TargetProperty="Height" />
                        <DoubleAnimation To="197" Storyboard.TargetName="TargetBtn" Storyboard.TargetProperty="Width" />
                      </Storyboard>
                    </BeginStoryboard>
                  </DataTrigger.ExitActions>
                </DataTrigger>
              </DataTemplate.Triggers>
            </DataTemplate>
          </ItemsControl.ItemTemplate>
        </ItemsControl>
      </Grid>
    </StackPanel>
  </Grid>
</UserControl>