Прикрепить ICommand в WPF UserControl

я реализовал простую кнопку с изображением в ней:

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

4 ответов


вы можете достичь этого гораздо более чистым способом, используя стиль и несколько вложенных свойств.

вложенные свойства будут хранить вашу конкретную информацию. Стиль будет использовать эти свойства и создать вы хотите посмотреть.

элемент по-прежнему будет кнопкой, поэтому команда и все остальное будут работать.

 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="..." />

Примечание:

Я уверен, что это будет очиститель, чтобы пройти через свойство " Template "и использовать ControlTemplate и TemplateBindings, но это означало бы воссоздание границы и других вещей вокруг вашего контента, поэтому, если вы хотите просто определить" контент " по умолчанию, мой пример будет способом, я думаю.


Если единственная добавленная функциональность, которую вы хотите для своей кнопки, - это изображение на ней, то я думаю, что вы приближаетесь к этому с неправильной стороны. WPF так же удивителен, как и потому, что элементы управления UI look-less. это означает, что элемент управления-это просто определение функциональности + некоторый шаблон для определения того, как он выглядит. Это означает, что шаблон может быть заменен в любое время, чтобы изменить внешний вид. Кроме того, почти любой контент может быть размещен внутри почти любого контроль

например, чтобы определить кнопку в вашем xaml, которая выглядит так, как вам нужно, это:

<Window ...>
    ...
    <Button Command="{Binding AttachContextCommand}">
        <StackPanel Orientation="Horizontal">
            <Image Source="{StaticResource AssociateImage}"/>
            <TextBlock Text="Associer"/>
        </StackPanel>
    </Button>
    ...
</Window>

просто имейте в виду, что с WPF вам не нужно определять новый CustomControl или UserControl каждый раз, когда вы хотите изменить внешний вид чего-то. Единственный раз, когда вам нужен CustomControl, - это если вы хотите добавить функциональность к существующему элементу управления или создать функциональность, которая не существует ни в одном другом Управление.

редактировать из-за комментария:

если вы хотите не определять содержимое для кнопки каждый раз, другой вариант-просто иметь класс poco (простой старый объект CLR), который определил бы все, что вас интересует (я напишу свой пример, как если бы вы делали это для панели инструментов, потому что это имеет смысл для меня):

public class ToolBarItem : INotifyPropertyChanged
{
    public string Text { get ... set ... }
    public ICommand Command { get ... set ... }
    public ImageSource Image { get ... set ... }
}

который имеет шаблон данных, определенный где-то (приложение.xaml, окно.Ресурсы, и т. д.):

<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, окружающий это. Теперь, когда я вспомнил это, я понимаю, что это не намного менее многословно, чем оригинал, где вы указываете содержимое вручную. Я опубликую новый ответ на помогите с вашим оригинальным вопросом.


повторно ответить на исходный вопрос:

Я думаю, что вы хотите создать новый CustomControl под названием ImageButton. Затем измените его на extend from Button вместо Control. Вам не понадобится свойство команды, так как Button уже имеет его. Вам нужно только добавить свойство Image, и вы можете повторно использовать свойство Content from button вместо свойства Text.

когда ваш CustomControl будет создан, он добавит запись в ваш Родовой.xaml для стиля по умолчанию вашего ImageButton. В сеттере для свойства шаблона можно изменить 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>

встроенная кнопка WPF содержит код, который запускает прикрепленную команду в ответ на щелчок. Ваш "ImageButton" происходит от UserControl, поэтому вы не получаете этого поведения. Вероятно, самый короткий маршрут, чтобы получить то, что вы хотите, для вашего класса ImageButton фактически является производным от класса кнопки WPF. Для этого измените разметку ImageButton на

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

до

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

затем измените базовый класс ImageButton на UserControl в Button.

вам, вероятно, придется внести некоторые другие незначительные изменения, прежде чем все это сработает.