问题
We have a ton of Buttons with an Icon and Text across the App, and I am trying to extract a common style for all of them. I came up with this idea of deriving from a Button and have a couple of dependency properties. This custom button class has a style common to all the Buttons in our Application.
My Custom Button definition:
<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); }
}
}
}
And I am using this control as follows:
<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>
Things look good, however the trigger is not firing when the bounded data changes. If I apply the same trigger to the regular button, it seems to be working fine.
Could you please tell me if I am missing something?
EDIT: Found an elegant solution. Made use of Attached Properties
回答1:
Add this line of code to your static constructor
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomToolBarButton), new FrameworkPropertyMetadata(typeof(CustomToolBarButton)));
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.defaultstylekey.aspx
回答2:
In your CustomToolBarButton
, you are setting it's DataContext
to the button itself(this.DataContext = this;
). By doing this you have stopped the propagation of the parent(parent control of your button, say grid or UserControl) data-context to your button(which contains the SelectedListItem
property).
In case you just want to fix this, try to use RelativeSource
or ElementName
Binding to access the buttons parent control and then use it's DataContext
to access the 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>
The problem is happening as you have used a UserControl to extend the Button; as you said you have a ton of buttons, I would suggest you to create a CustomControl
with template, like this; that way you won't have to mess with the DataContext propagation.
Here is a blog explaining different ways of doing exactly what you want -
http://blogs.msdn.com/b/knom/archive/2007/10/31/wpf-control-development-3-ways-to-build-an-imagebutton.aspx
回答3:
First of all you should never use this.DataContext = this;, ever.
Secondly if you inherit from button you should not create a XAML file but a default style in the Themes/Generic.xaml
resource dictionary (if you inherit from UserControl
a file like this is fine).
This will also mean that you will need to define a Control.Template in the style and hence should use TemplateBindings instead of normal ones (or use RelativeSource).
As noted in another answer you may need to override the metadata.
来源:https://stackoverflow.com/questions/13464735/datatrigger-does-not-fire-on-a-derived-class-of-a-button