代码之家  ›  专栏  ›  技术社区  ›  Mike Eason

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

  •  0
  • Mike Eason  · 技术社区  · 9 年前

    我有以下自定义控件:

    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为 没有一个 ,然后显示默认图像,否则显示 忙碌的 图像,非常简单。以下是样式:

    <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>
    

    问题出在 数据触发器 ,它没有获取依赖属性 状态 。将控件添加到视图后,我在输出中收到以下错误:

    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')
    

    读取该错误消息时,它似乎正在查找 状态 上的属性 工作区视图模型 而不是依赖属性所属的控件。这是为什么?

    1 回复  |  直到 9 年前
        1
  •  1
  •   Clemens    9 年前

    DataTriggers中的Bindings(正确)期望State属性位于控件的DataContext中。但您希望在控件本身的属性值上触发。

    因此,您应该使用Triggers而不是DataTriggers:

    <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>