我实现了一个带有图像的简单按钮:
<Button Command="{Binding ButtonCommand, ElementName=ImageButtonControl}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ButtonImage, ElementName=ImageButtonControl}"/>
<TextBlock Text="{Binding ButtonText, ElementName=ImageButtonControl}" Margin="2,0,0,0"/>
</StackPanel>
</Button>
如您所见,我公开了一个ButtonCommand属性,以便能够将ICommand附加到此UserControl:
public partial class ImageButton : UserControl
{
/// <summary>
/// The dependency property that gets or sets the source of the image to render.
/// </summary>
public static DependencyProperty ImageSourceProperty =
DependencyProperty.Register("ButtonImage", typeof(ImageSource), typeof(ImageButton));
public static DependencyProperty TextProperty =
DependencyProperty.Register("ButtonText", typeof(string), typeof(ImageButton));
public static DependencyProperty ButtonCommandProperty =
DependencyProperty.Register("ButtonCommand", typeof(ICommand), typeof(ImageButton));
public ImageButton()
{
this.DataContext = this;
InitializeComponent();
}
/// <summary>
/// Gets or sets the button command.
/// </summary>
public ICommand ButtonCommand
{
get { return (ICommand)GetValue(ImageButton.ButtonCommandProperty); }
set { SetValue(ImageButton.ButtonCommandProperty, value); }
}
/// <summary>
/// Gets or sets the button image.
/// </summary>
public ImageSource ButtonImage
{
get { return (ImageSource)GetValue(ImageButton.ImageSourceProperty); }
set { SetValue(ImageButton.ImageSourceProperty, value); }
}
/// <summary>
/// Gets or sets the button text.
/// </summary>
public string ButtonText
{
get { return (string)GetValue(ImageButton.TextProperty); }
set { SetValue(ImageButton.TextProperty, value); }
}
}
然后,当我宣布我的按钮时,它会给出:
<uc:ImageButton Grid.Row="1" Grid.Column="0" ButtonCommand="{Binding AttachContextCommand}" ButtonImage="{StaticResource AssociateImage}" ButtonText="Associer"/>
而且badaboom,当我点击我的ImageButton时,什么都不会发生。 当我用一个简单的按钮替换ImageButton时,会调用ICommand。
我甚至试图简单地扩展Button类并绑定一个ICommand,但是再一次,它没有用......
帮助表示赞赏!
THX。
答案 0 :(得分:7)
您可以使用样式和一些附加属性以更清晰的方式实现此目的。
附加属性将存储您的特定信息。 该样式将使用这些属性并构建您想要的外观。
元素仍然是一个按钮,所以命令和其他一切都可以工作。
public class ImageButton
{
public static ImageSource GetImage(DependencyObject obj)
{
return (ImageSource)obj.GetValue(ImageProperty);
}
public static void SetImage(DependencyObject obj, ImageSource value)
{
obj.SetValue(ImageProperty, value);
}
public static readonly DependencyProperty ImageProperty =
DependencyProperty.RegisterAttached("Image", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));
public static String GetCaption(DependencyObject obj)
{
return (String)obj.GetValue(CaptionProperty);
}
public static void SetCaption(DependencyObject obj, String value)
{
obj.SetValue(CaptionProperty, value);
}
public static readonly DependencyProperty CaptionProperty =
DependencyProperty.RegisterAttached("Caption", typeof(String), typeof(ImageButton), new UIPropertyMetadata(null));
}
<Style TargetType="{x:Type Button}"
x:Key="ImageButton">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=(local:ImageButton.Image), RelativeSource={RelativeSource AncestorType={x:Type Button}}}" />
<TextBlock Text="{Binding Path=(local:ImageButton.Caption), RelativeSource={RelativeSource AncestorType={x:Type Button}}}"
Margin="2,0,0,0" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
然后您可以使用它来声明按钮:
<Button Style="{DynamicResource ImageButton}"
local:ImageButton.Caption="Foo"
local:ImageButton.Image="..." />
注意:
我很确定通过“模板”属性并使用ControlTemplate和TemplateBindings会更干净,但这意味着要重新创建内容周围的边框和其他内容,所以如果你只是想定义一个默认的“内容”,我想我的例子就是这样。
答案 1 :(得分:4)
如果您想要为按钮添加的唯一功能是在其上添加图像,那么我认为您正在从错误的方向接近此功能。 WPF非常棒,因为UI控件无外观。这意味着Control只是一个功能定义+一些模板来定义它的外观。这意味着可以随时换出模板以更改外观。此外,几乎任何内容都可以放在几乎任何控件内部
例如,要在xaml中定义一个具有您所需要的外观的按钮,请执行以下操作:
<Window ...>
...
<Button Command="{Binding AttachContextCommand}">
<StackPanel Orientation="Horizontal">
<Image Source="{StaticResource AssociateImage}"/>
<TextBlock Text="Associer"/>
</StackPanel>
</Button>
...
</Window>
请记住,使用WPF时,每次要更改某些内容的外观时,都不必定义新的CustomControl或UserControl。您应该需要CustomControl的唯一时间是您要为现有Control添加功能或创建任何其他Control中不存在的功能。
编辑由于评论:
如果你想每次都不想定义按钮的内容,另一个选择是只有一个poco(普通的旧CLR对象)类来定义你感兴趣的一切(我会写我的例子)好像你正在为工具栏做这个,因为它对我有意义):
public class ToolBarItem : INotifyPropertyChanged
{
public string Text { get ... set ... }
public ICommand Command { get ... set ... }
public ImageSource Image { get ... set ... }
}
在某处定义了数据模板(App.xaml,Window.Resources等):
<DataTemplate DataType="{x:Type l:ToolBarItem}">
<Button Command="{Binding Command}">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</Button>
</DataTemplate>
然后在你的xaml中使用这样的人:
<Window ...>
...
<ContentControl>
<ContentControl.Content>
<l:ToolBarItem Image="..." Command="..." Text="..."/>
</ContentControl.Content>
</ContentControl>
...
</Window>
我只是不知道你尝试这样做的方式是你可以做到的最WPF方式。
编辑根据第二条评论更新 对不起,我忘了包含ContentControl。现在我记得那个,我意识到,这比你手动指定内容的原始文件要简单得多。我会发布一个新的答案来帮助你解决原始问题。
答案 2 :(得分:1)
重新回答原来的问题:
我认为你想要做的是创建一个名为 ImageButton 的新CustomControl。然后将其更改为从Button而不是Control扩展。您不需要Command属性,因为Button已经有一个。您只需要添加一个Image属性,并且可以从按钮重用Content属性而不是Text属性。
创建CustomControl后,它会在Generic.xaml中添加一个条目,用于ImageButton的默认样式。在Setter for Template属性中,您可以将ControlTemplate更改为:
<ControlTemplate TargetType="{x:Type local:ImageButton}">
<StackPanel Orientation="Horizontal">
<Image Source="{TemplateBinding Image}"/>
<ContentPresenter/>
</StackPanel>
</ControlTemplate>
然后,当你想要使用它时:
<Window ... >
...
<l:ImageButton Image="{StaticResource ...}" Command="...">
Associer
</l:ImageButton>
...
</Window>
答案 3 :(得分:0)
内置WPF按钮包含触发附加命令以响应单击的代码。您的“ImageButton”派生自UserControl,因此您不会获得该行为。获得所需内容的最短路径可能是您的ImageButton类实际派生自WPF Button类。要完成此操作,请从
更改ImageButton的标记<UserControl
...
>
...
</UserControl>
到
<Button
...
>
...
</Button>
然后将ImageButton的基类从UserControl
更改为Button
。
在一切正常之前,你可能需要做一些其他的小改动。