将情节提要的目标设置为 DataTemplate WPF 中的按钮
Posted
技术标签:
【中文标题】将情节提要的目标设置为 DataTemplate WPF 中的按钮【英文标题】:Set Target of Storyboard to Button inside a DataTemplate WPF 【发布时间】:2021-05-24 14:48:35 【问题描述】:我们正在尝试根据窗口大小设置按钮的高度和宽度。我们希望使用视觉状态来实现这一点。我们想将 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);
提前致谢。
【问题讨论】:
【参考方案1】:不能使用视觉状态动画来为DataTemplate
中的属性设置动画。 DataTemplate
只是一个模板,它不是可视化树的一部分,在定义故事板的那一刻。将为每个模板化目标复制模板,例如每个项目容器。这意味着将有多个名称为 TargetBtn
的按钮 - 从模板范围之外查看时。因此,您必须将动画移动到 DataTemplate
范围内,这意味着在模板内部。
除了控件的视觉状态定义之外,您还应该添加属性以将视觉状态反映为对象状态。
Microsoft Docs 建议对每个状态执行此操作是最佳做法:添加属性如 IsMouseOver
以指示 MouseOver
状态或 IsFocused
与 Focused
状态串联,仅举一些框架示例.
这允许您的控件将视觉状态表达为真实的实例状态,可以在控件的直接内容的上下文之外使用 - 视觉状态只能由 VisualStateManager
使用。
然后您可以使用这个通常是公共的只读依赖属性来触发,例如一个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>
【讨论】:
非常感谢!这是有效的。主要应用程序遵循 MVVM 模式。我之前确实尝试通过绑定 ViewModel 的属性来使用 DataTrigger。但这没有用。以上是关于将情节提要的目标设置为 DataTemplate WPF 中的按钮的主要内容,如果未能解决你的问题,请参考以下文章
一起使用笔尖和情节提要:将笔尖的按钮目标/动作连接到情节提要中的控制器
无法将 Action 设置为在情节提要上创建的 UIBarButtonItem
如何在情节提要 Xcode 11 中的视图之间将边距设置为零