SuspendedButton - 如何暂停 WPF 按钮的点击事件





5.00/5 (3投票s)
本文档展示了如何扩展 Button 控件,以支持暂停其点击事件,以便在点击事件触发之前执行一些动画。
在开发 WPF 视图 (XAML) 时,我们有时希望给用户一个移除视图中某些元素的选项。
通常,为了实现这一点,我们将 ICommandSource
(Button
、MenuItem
等) 的 Command
属性绑定到视图模型中的 Command
(类型实现 ICommand
的属性)。
有时,我们希望在移除元素时对其执行动画。现在,我们遇到了一个问题。假设我们有一个按钮,它绑定到视图模型中的移除命令。当我们点击此按钮时,Click
事件被触发,绑定的命令被执行。在命令执行完毕后,动画要作用的元素已经移除。所以,如果我们只有在按钮点击时才知道移除操作,并且在按钮点击后立即移除元素,我们何时才能执行动画?
为了解决这个问题,我们可以通过创建一个从 Button
派生的类来扩展 Button
控件,并添加所需的功能,如下所示
public class SuspendedButton : Button
{
#region SuspendTime
public TimeSpan SuspendTime
{
get { return (TimeSpan)GetValue(SuspendTimeProperty); }
set { SetValue(SuspendTimeProperty, value); }
}
public static readonly DependencyProperty SuspendTimeProperty =
DependencyProperty.Register("SuspendTime", typeof(TimeSpan), typeof(SuspendedButton), new UIPropertyMetadata(TimeSpan.Zero));
#endregion
#region BeforeClick
public static readonly RoutedEvent BeforeClickEvent = EventManager.RegisterRoutedEvent(
"BeforeClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(SuspendedButton));
public event RoutedEventHandler BeforeClick
{
add { AddHandler(BeforeClickEvent, value); }
remove { RemoveHandler(BeforeClickEvent, value); }
}
#endregion
protected override void OnClick()
{
RaiseEvent(new RoutedEventArgs(SuspendedButton.BeforeClickEvent));
TimeSpan time = SuspendTime;
ThreadPool.QueueUserWorkItem(new WaitCallback(o =>
{
Thread.Sleep(time);
Dispatcher.BeginInvoke(DispatcherPriority.Normal,
new ThreadStart(() =>
{
base.OnClick();
}));
}));
}
}
此控件的 SuspendTime
属性可用于指定在实际点击和触发 Click
事件之间需要等待的时间。 我们可以设置动画的持续时间。
此控件的 BeforeClick
事件在实际点击时触发,允许我们在 Click
事件触发之前执行动画。
例如,请查看以下 ItemsControl
<ItemsControl ItemsSource="{Binding MyItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<Storyboard x:Key="hideItemStoryboard">
<DoubleAnimation Storyboard.TargetName="mainBorder"
Storyboard.TargetProperty="(FrameworkElement.LayoutTransform).(ScaleTransform.ScaleY)"
To="0"
Duration="0:0:0.2" />
</Storyboard>
</DataTemplate.Resources>
<Border x:Name="mainBorder"
BorderThickness="1"
BorderBrush="Black"
CornerRadius="3"
Margin="2">
<Border.LayoutTransform>
<ScaleTransform ScaleY="1" />
</Border.LayoutTransform>
<DockPanel Margin="2">
<local:SuspendedButton x:Name="btnRemove"
Content="Remove"
SuspendTime="0:0:0.2"
DockPanel.Dock="Left"
VerticalAlignment="Center"
Command="{Binding RemoveCommand}"
Margin="5,0"/>
<TextBlock Text="{Binding Name}" />
</DockPanel>
</Border>
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="local:SuspendedButton.BeforeClick"
SourceName="btnRemove">
<BeginStoryboard Storyboard="{StaticResource hideItemStoryboard}" />
</EventTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
此 ItemsControl
具有一个 ItemTemplate
,其中包含:一个用于移除操作的动画的 Storyboard
,一个绑定到移除命令的 SuspendedButton
,以及一个在 BeforeClick
事件触发时执行移除动画的 EventTrigger
。 当用户点击移除按钮时,将执行移除动画,然后移除该元素。