65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIconstarIcon

5.00/5 (3投票s)

2011年10月4日

CPOL

2分钟阅读

viewsIcon

18911

本文档展示了如何扩展 Button 控件,以支持暂停其点击事件,以便在点击事件触发之前执行一些动画。

在开发 WPF 视图 (XAML) 时,我们有时希望给用户一个移除视图中某些元素的选项。

通常,为了实现这一点,我们将 ICommandSource (ButtonMenuItem 等) 的 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。 当用户点击移除按钮时,将执行移除动画,然后移除该元素。

© . All rights reserved.