我们在应用程序中有大量带有图标和文本的按钮,我正在尝试为所有这些按钮提取一个共同的样式。我想出了从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。利用附加属性
答案 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
属性)。
如果您只想解决此问题,请尝试使用RelativeSource
或ElementName
绑定来访问父控件按钮,然后使用它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的传播。
这是一篇博客,解释了完全按照自己的意愿行事的不同方法 -
答案 2 :(得分:0)
首先,你应该never use this.DataContext = this;
,永远。
其次,如果从按钮继承,则不应创建XAML文件,而应在Themes/Generic.xaml
资源字典中创建默认样式(如果从UserControl
继承这样的文件就可以了。)
这也意味着您需要在样式中定义Control.Template
,因此应使用TemplateBindings
代替普通代码(或使用RelativeSource
)。
如another answer所述,您可能需要覆盖元数据。