覆盖的元数据仍在子自定义控件中执行 class

Overriden metadata are still executed in a children custom control class

我在我制作的 "button" 自定义控件中创建了一个 DP:

#region IsPressed
public bool IsPressed {
    get { return (bool)GetValue(IsPressedProperty); }
    private set { SetValue(IsPressedProperty, value); }
}

private static void IsPressedCallback(DependencyObject o, DependencyPropertyChangedEventArgs args) {
    MyParentClass btn = (MyParentClass) o;
    //change the background when the "button" is pressed, change it back afterward
    if ((bool) args.NewValue) {
        btn._backgroundBrushTemp = btn.Background;
        btn.Background = btn._pressBrush;
    } else {
        btn.Background = btn._backgroundBrushTemp;
    }
}

private readonly static PropertyMetadata IsPressedMetadata = new PropertyMetadata() {
    DefaultValue = false,
    PropertyChangedCallback = IsPressedCallback
};

public static readonly DependencyProperty IsPressedProperty = 
    DependencyProperty.Register("IsPressed", typeof(bool), typeof(MyParentClass), IsPressedMetadata);
#endregion

一切都按预期工作,但用户现在想要一种新行为,使我的自定义控件方式不那么通用,所以我创建了另一个自定义控件:继承 MyParentClass 的 MyChildrenClass。

为了实现新行为,我必须重写 IsPressed 的回调函数,所以我在 MyChildrenClass 的静态构造器中写了这个:

IsPressedProperty.OverrideMetadata(
    typeof(MyChildrenClass),
    new FrameworkPropertyMetadata(false, IsPressedCallback)
);

并编写了新的回调:

private static void IsPressedCallback(DependencyObject o, DependencyPropertyChangedEventArgs args) {
    MyChildrenClass btn = (MyChildrenClass)o;

    //change the background when the "button" is pressed, change it back after 1s
    if ((bool) args.NewValue) {
        btn._backgroundBrushTemp = btn.Background;
        btn.Background = btn._pressBrush;
        if (btn._threadIsPressed == null ||
            !btn._threadIsPressed.IsAlive) {
            btn._threadIsPressed = new Thread(() => {
                Thread.Sleep(1000);
                btn.Dispatcher.BeginInvoke(new Action(() => {
                    btn.Background = btn._backgroundBrushTemp;
                }));
            });
            btn._threadIsPressed.Start();
        }
    }
}

现在的问题是:尽管我已经覆盖了元数据和回调函数,但两个回调都被调用了。我做错了什么?

设法完全在 XAML 完成:

<!--Standard brushes-->
<ImageBrush x:Key="BrushBtnIdle">
    <ImageBrush.ImageSource>
        <BitmapImage>
            <BitmapImage.UriSource>
                <system1:Uri>pack://application:,,,/AssemblyName;component/Resources/Images/Btn_Idle.png
                </system1:Uri>
            </BitmapImage.UriSource>
        </BitmapImage>
    </ImageBrush.ImageSource>
</ImageBrush>
<ImageBrush x:Key="BrushBtnPushed">
    <ImageBrush.ImageSource>
        <BitmapImage>
            <BitmapImage.UriSource>
                <system1:Uri>pack://application:,,,/AssemblyName;component/Resources/Images/Btn_Pushed.png
                </system1:Uri>
            </BitmapImage.UriSource>
        </BitmapImage>
    </ImageBrush.ImageSource>
</ImageBrush>
<Style TargetType="{x:Type local:MyParentClass}">
    <Setter Property="Background" Value="White"/>
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property="HorizontalContentAlignment" Value="Center"/>
    <Setter Property="VerticalContentAlignment" Value="Center"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:MyParentClass}">

                <Border Background="{TemplateBinding Background}"
                        Margin="{TemplateBinding Margin}"
                        BorderBrush="{TemplateBinding BorderBrush}" 
                        SnapsToDevicePixels="true"
                        Opacity="{TemplateBinding Opacity}"
                        CornerRadius="{TemplateBinding Border.CornerRadius}" 
                        Padding="{TemplateBinding Padding}">
                    <ContentPresenter  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                       Margin="{TemplateBinding Padding}" 
                                       RecognizesAccessKey="True" 
                                       SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                       VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="IsPressed" Value="True">
            <Setter Property="Background" Value="{StaticResource BrushBtnPushed}"/>
        </Trigger>
        <Trigger Property="IsPressed" Value="False">
            <Setter Property="Background" Value="{StaticResource BrushBtnIdle}"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="False">
            <Setter Property="Opacity" Value=".5"/>
        </Trigger>
    </Style.Triggers>
</Style>
<!--Highlighted button-->
<ImageBrush x:Key="BrushBtnHighlight">
    <ImageBrush.ImageSource>
        <BitmapImage>
            <BitmapImage.UriSource>
                <system1:Uri>pack://application:,,,/AssemblyName;component/Resources/Images/ActivatedBtn.png
                </system1:Uri>
            </BitmapImage.UriSource>
        </BitmapImage>
    </ImageBrush.ImageSource>
</ImageBrush>
<Style TargetType="{x:Type local:MyChildrenClass}" BasedOn="{StaticResource {x:Type local:MyParentClass}}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding RelativeSource={RelativeSource self}, Path=IsPressed}" Value="True">
            <DataTrigger.EnterActions>
                <BeginStoryboard>
                    <Storyboard TargetProperty="Background">
                        <ObjectAnimationUsingKeyFrames Duration="00:00:01" FillBehavior="Stop">
                            <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{StaticResource BrushBtnHighlight}"/>
                        </ObjectAnimationUsingKeyFrames>
                    </Storyboard>
                </BeginStoryboard>
            </DataTrigger.EnterActions>
        </DataTrigger>
    </Style.Triggers>
</Style>

在 DataTrigger 中使用 StoryBoard 而不是 Thread.Sleep。