在数据触发器中使用依赖项 属性

Using a Dependency Property in a Data Trigger

我有以下自定义控件:

public class AnimatedButton : Button
    {
        public enum ButtonStates
        {
            None,
            Busy
        }

        public ButtonStates State
        {
            get { return (ButtonStates)GetValue(StateProperty); }
            set { SetValue(StateProperty, value); }
        }

        // Using a DependencyProperty as the backing store for State.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty StateProperty =
            DependencyProperty.Register("State", typeof(ButtonStates), typeof(AnimatedButton), new PropertyMetadata(ButtonStates.None));

        public ImageSource ImageDefault
        {
            get { return (ImageSource)GetValue(ImageDefaultProperty); }
            set { SetValue(ImageDefaultProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ImageDefault.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageDefaultProperty =
            DependencyProperty.Register("ImageDefault", typeof(ImageSource), typeof(AnimatedButton), new PropertyMetadata(null));

        public ImageSource ImageBusy
        {
            get { return (ImageSource)GetValue(ImageBusyProperty); }
            set { SetValue(ImageBusyProperty, value); }
        }

        ...
    }

我的目的是根据当前按钮状态显示适当的图像源。例如,如果 ButtonState 为 None,则显示默认图像,否则显示 Busy 图像,非常简单。这是样式:

<Style TargetType="{x:Type controls:AnimatedButton}">
    ...
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type controls:AnimatedButton}">
                <Border>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>

                        <Image x:Name="img"/>

                        <TextBlock Text="{TemplateBinding Content}"
                                   Grid.Column="1"/>
                    </Grid>
                </Border>

                <ControlTemplate.Triggers>
                    <DataTrigger Binding="{Binding State}" Value="None">
                        <Setter TargetName="img" Property="Source" Value="{Binding ImageDefault}"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding State}" Value="Busy">
                        <Setter TargetName="img" Property="Source" Value="{Binding ImageBusy}"/>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

问题出在 DataTrigger,它没有获取依赖项 属性 State。将控件添加到视图后,我在输出中收到以下错误:

System.Windows.Data Error: 40 : BindingExpression path error: 'State' property not found on 'object' ''WorkspaceViewModel' (HashCode=56037929)'. BindingExpression:Path=State; DataItem='WorkspaceViewModel' (HashCode=56037929); target element is 'AnimatedButton' (Name=''); target property is 'NoTarget' (type 'Object')

阅读该错误消息,它似乎正在寻找 WorkspaceViewModel 上的 State 属性 而不是依赖项 属性 所属的控件。这是为什么?

DataTriggers 中的绑定(正确地)期望状态 属性 位于控件的 DataContext 中。但是您想触发控件本身的 属性 的值。

因此您应该使用触发器而不是数据触发器:

<ControlTemplate.Triggers>
    <Trigger Property="State" Value="None">
        <Setter TargetName="img" Property="Source"
            Value="{Binding ImageDefault, RelativeSource={RelativeSource TemplatedParent}}"/>
    </Trigger>
    <Trigger Property="State" Value="Busy">
        <Setter TargetName="img" Property="Source"
            Value="{Binding ImageBusy, RelativeSource={RelativeSource TemplatedParent}}"/>
    </Trigger>
</ControlTemplate.Triggers>