7

我实现了一个带有图像的简单按钮:

    <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,但再一次,它没有工作......

帮助表示赞赏!

谢谢。

4

4 回答 4

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 会更干净,但这意味着在您的内容周围重新创建边框和其他内容,所以如果您只想定义一个默认值“内容”,我认为我的例子是要走的路。

于 2009-03-16T14:17:54.160 回答
4

如果您想要为按钮添加的唯一功能是在其上添加图像,那么我认为您从错误的方向接近这个。WPF 非常棒,因为它的 UI 控件看起来很少。 这意味着控件只是功能的定义+一些模板来定义它的外观。这意味着可以随时更换模板以更改外观。此外,几乎任何内容都可以放在几乎任何控件中

例如,要在您的 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。现在我想起了这一点,我意识到这并不比您手动指定内容的原始版本少多少。我将发布一个新答案以帮助您解决原始问题。

于 2009-03-14T04:38:09.757 回答
1

要重新回答原始问题:

我认为您想要做的是创建一个名为ImageButton的新 CustomControl 。然后将其更改为从 Button 而不是 Control 扩展。您不需要 Command 属性,因为 Button 已经有一个。您只需要添加一个 Image 属性,就可以重用按钮的 Content 属性,而不是 Text 属性。

创建 CustomControl 后,它将在 Generic.xaml 中为 ImageButton 的默认样式添加一个条目。在 Template 属性的 Setter 中,您可以将 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>
于 2009-03-16T17:42:58.737 回答
0

内置 WPF 按钮包含触发附加命令以响应单击的代码。您的“ImageButton”派生自 UserControl,因此您不会得到这种行为。获得所需内容的最短路径可能是让 ImageButton 类实际派生自 WPF Button 类。为此,将 ImageButton 的标记从

<UserControl
...
>
...
</UserControl>

<Button
...
>
...
</Button>

然后将 ImageButton 的基类从 更改UserControlButton

在一切正常之前,您可能需要进行一些其他小的更改。

于 2009-03-13T18:23:48.030 回答