DataTrigger不会触发Button的派生类

时间:2012-11-20 00:17:26

标签: wpf button dependency-properties multidatatrigger

我们在应用程序中有大量带有图标和文本的按钮,我正在尝试为所有这些按钮提取一个共同的样式。我想出了从Button派生并拥有几个依赖属性的想法。此自定义按钮类具有应用程序中所有按钮共有的样式。

我的自定义按钮定义:

<Button x:Class="UIElements.Controls.CustomToolBarButton"
               xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
               xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
               xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
               xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
               xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" mc:Ignorable="d"
               >
<!--Style="{StaticResource ResourceKey=ToolBarButtonStyle}"-->
<StackPanel Orientation="Horizontal">
    <Image Source="{Binding Icon, Mode=TwoWay}" Style="{StaticResource ResourceKey=ToolBarButtonIconStyle}" />
    <TextBlock Text="{Binding DisplayText, Mode=TwoWay}" Style="{StaticResource ResourceKey=ToolBarButtonDisplayTextStyle}" />
</StackPanel>

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
//using Telerik.Windows.Controls;

namespace UIElements.Controls
{
    public partial class CustomToolBarButton : Button
    {
        public CustomToolBarButton()
        {
            InitializeComponent();
            this.DataContext = this;
        }

        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register("Icon", typeof(BitmapImage), typeof(Button), new PropertyMetadata(default(BitmapImage)));

        public BitmapImage Icon
        {
            get { return (BitmapImage)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        public static readonly DependencyProperty DisplayTextProperty =
            DependencyProperty.Register("DisplayText", typeof(string), typeof(Button), new PropertyMetadata(default(string)));

        public string DisplayText
        {
            get { return (string) GetValue(DisplayTextProperty); }
            set { SetValue(DisplayTextProperty, value); }
        }
    }
}

我正在使用此控件,如下所示:

<Controls1:CustomToolBarButton Icon="{DynamicResource ImageSave}"
                        DisplayText="Test Display">
<Controls1:CustomToolBarButton.Style>
    <Style TargetType="Controls1:CustomToolBarButton">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding SelectedListItem.ListId}" Value="0" />
                </MultiDataTrigger.Conditions>
                <!--<Setter Property="Button.IsEnabled" Value="False" />-->
                <Setter Property="Background" Value="BurlyWood" />
            </MultiDataTrigger>
        </Style.Triggers>
    </Style>
</Controls1:CustomToolBarButton.Style>

事情看起来不错,但是当有界数据发生变化时,触发器不会触发。如果我将相同的触发器应用于常规按钮,它似乎工作正常。

如果我遗失了什么,请你告诉我吗?

修改 找到elegant solution。利用附加属性

3 个答案:

答案 0 :(得分:0)

将这行代码添加到静态构造函数

DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomToolBarButton), new FrameworkPropertyMetadata(typeof(CustomToolBarButton)));

http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.defaultstylekey.aspx

答案 1 :(得分:0)

CustomToolBarButton中,您要将DataContext设置为按钮本身(this.DataContext = this;)。通过执行此操作,您已停止将父级(按钮的父控件,例如grid或UserControl)数据上下文传播到按钮(包含SelectedListItem属性)。

如果您只想解决此问题,请尝试使用RelativeSourceElementName绑定来访问父控件按钮,然后使用它DataContext访问{ {1}}。

SelectedListItem

当您使用UserControl扩展Button时,问题就出现了;正如你所说,你有很多按钮,我建议你创建一个<Grid x:Name="ParentGrid"> <Controls1:CustomToolBarButton Icon="{DynamicResource ImageSave}" DisplayText="Test Display"> <Controls1:CustomToolBarButton.Style> <Style TargetType="Controls1:CustomToolBarButton"> <Style.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding ElementName=ParentGrid, Path=DataContext.SelectedListItem.ListId}" Value="0" /> </MultiDataTrigger.Conditions> <!--<Setter Property="Button.IsEnabled" Value="False" />--> <Setter Property="Background" Value="BurlyWood" /> </MultiDataTrigger> </Style.Triggers> </Style> </Controls1:CustomToolBarButton.Style> </Grid> 模板,如this;这样你就不必混淆DataContext的传播。

这是一篇博客,解释了完全按照自己的意愿行事的不同方法 -

http://blogs.msdn.com/b/knom/archive/2007/10/31/wpf-control-development-3-ways-to-build-an-imagebutton.aspx

答案 2 :(得分:0)

首先,你应该never use this.DataContext = this;,永远。

其次,如果从按钮继承,则不应创建XAML文件,而应在Themes/Generic.xaml资源字典中创建默认样式(如果从UserControl继承这样的文件就可以了。)

这也意味着您需要在样式中定义Control.Template,因此应使用TemplateBindings代替普通代码(或使用RelativeSource)。

another answer所述,您可能需要覆盖元数据。