【问题标题】:DataTrigger does not fire on a derived class of a ButtonDataTrigger 不会在 Button 的派生类上触发
【发布时间】:2012-11-08 00:29:16
【问题描述】:

我们在整个应用程序中有大量带有图标和文本的按钮,我正在尝试为所有这些按钮提取一个共同的样式。我想出了这个从 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。使用附加属性

【问题讨论】:

    标签: wpf button dependency-properties multidatatrigger


    【解决方案1】:

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

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

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

    【讨论】:

    • 更多信息?您是否在输出、绑定错误等方面得到任何信息?
    【解决方案2】:

    在您的CustomToolBarButton 中,您将它的DataContext 设置为按钮本身(this.DataContext = this;)。通过这样做,您已停止将父级(按钮的父控件,例如网格或 UserControl)数据上下文传播到您的按钮(其中包含 SelectedListItem 属性)。

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

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

    问题正在发生,因为您使用了 UserControl 来扩展 Button;正如您所说,您有很多按钮,我建议您使用模板创建一个CustomControl,例如this;这样您就不必弄乱 DataContext 传播。

    这是一个博客,解释了做你想做的事情的不同方法 -

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

    【讨论】:

    • 谢谢 Akjoshi,在博客的链接中,有一条评论提到使用附加属性来实现相同的目的..
    • 是的,使用内容模板也是一个好方法。
    【解决方案3】:

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

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

    这也意味着您需要在样式中定义Control.Template,因此应该使用TemplateBindings 而不是普通的(或使用RelativeSource)。

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

    【讨论】:

      猜你喜欢
      • 2016-06-12
      • 2013-03-16
      • 1970-01-01
      • 2012-06-22
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      相关资源
      最近更新 更多