Как создать простую кнопку WPF UserControl с настраиваемыми включенными / отключенными изображениями?

Я немного новичок в WPF и XAML, сейчас только учусь.

Я нашел быстрый и грязный код от какого-то предыдущего разработчика:

<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type Button}">
        <Border Name="buttonBorder" Background="{TemplateBinding Background}">
            <Border.Effect>
                <DropShadowEffect Opacity="0.0" />
            </Border.Effect>
        </Border>
        <ControlTemplate.Triggers>
            <Trigger Property="IsMouseOver" Value="true">
                <Setter TargetName="buttonBorder" Property="Effect">
                    <Setter.Value>
                        <DropShadowEffect Opacity="0.8" />
                    </Setter.Value>
                </Setter>
            </Trigger>
            <Trigger Property="IsMouseCaptured" Value="true">
                    <Setter TargetName="buttonBorder" Property="Effect">                   
                         <Setter.Value>
                        <DropShadowEffect Opacity="0.8" Direction="135"  
                             ShadowDepth="3" BlurRadius="1" />
                        </Setter.Value>
                    </Setter>
                </Trigger>
            <Trigger Property="IsEnabled" Value="false">
                   <Setter TargetName="buttonBorder" Property="Background">
                        <Setter.Value>
                        <ImageBrush ImageSource="{Binding Path=Tag, RelativeSource={RelativeSource TemplatedParent}}"  />
                        </Setter.Value>
                    </Setter>            
                   <Setter TargetName="buttonBorder" Property="Effect">
                    <Setter.Value>
                        <DropShadowEffect Opacity="0.0"/>
                    </Setter.Value>
                </Setter>     

            </Trigger>
        </ControlTemplate.Triggers>
        </ControlTemplate>

По сути, это просто шаблон для кнопки с базовым эффектом наведения мыши и изображение для отключенного состояния, привязанного к тегу (кажется уродливым решением).

Я хочу создать настраиваемую кнопку, которая работает примерно так же, но я хочу предоставить два настраиваемых свойства: NormalImage и DisabledImage. Эти свойства должны быть строкового типа, а не Uri. Я хочу использовать путь к изображению только «apply.png», а не «pack: // application: ,,, / Resources / Apply.png». Я думаю, чтобы иметь такие настраиваемые свойства, мне нужен UserControl со свойствами зависимости?

По сути, я хочу использовать кнопку следующим образом:

<MyImageButton NormalImage="apply.png" DisabledImage="apply_disabled.png"/>

Возможно, NormalImage / DisabledImage будет привязан к чему-то позже, но это маловероятно.

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

Может ли кто-нибудь указать мне нужную статью или добавить простой фрагмент кода, с которым можно поиграться?

WPF настолько сложен для новичков, что иногда он просто не работает должным образом, например, я до сих пор не понимаю, почему я могу добавить тег Trigger в ControlTemplate, но я не могу добавить тег Trigger прямо в UserControl ...


person JustAMartin    schedule 13.02.2011    source источник


Ответы (3)


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

Xaml:

<UserControl x:Class="Test.ImageButton"
             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" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             DataContext="{Binding RelativeSource={RelativeSource Self}}">
    <Button Name="button" Click="button_Click" Width="50" Height="50">
        <Button.Template>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border Name="buttonBorder">
                    <Border.Effect>
                        <DropShadowEffect Opacity="0.0" />
                    </Border.Effect>
                    <Border.Child>
                        <Image Name="img" Source="{Binding NormalImage}"/>
                    </Border.Child>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="buttonBorder" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect Opacity="0.8" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsMouseCaptured" Value="true">
                        <Setter TargetName="buttonBorder" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect Opacity="0.8" Direction="135"  
                             ShadowDepth="3" BlurRadius="1" />
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter TargetName="img" Property="Source" Value="{Binding DisabledImage}"/>
                        <Setter TargetName="buttonBorder" Property="Effect">
                            <Setter.Value>
                                <DropShadowEffect Opacity="0.0"/>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Button.Template>
    </Button>
</UserControl>

Код позади:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace Test
{
    /// <summary>
    /// Interaction logic for ImageButton.xaml
    /// </summary>
    public partial class ImageButton : UserControl
    {
        public ImageSource DisabledImage
        {
            get { return (ImageSource)GetValue(DisabledImageProperty); }
            set { SetValue(DisabledImageProperty, value); }
        }
        public static readonly DependencyProperty DisabledImageProperty =
            DependencyProperty.Register("DisabledImage", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));


        public ImageSource NormalImage
        {
            get { return (ImageSource)GetValue(NormalImageProperty); }
            set { SetValue(NormalImageProperty, value); }
        }
        public static readonly DependencyProperty NormalImageProperty =
            DependencyProperty.Register("NormalImage", typeof(ImageSource), typeof(ImageButton), new UIPropertyMetadata(null));

        public event RoutedEventHandler Click;

        public ImageButton()
        {
            InitializeComponent();
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            if (Click != null)
            {
                Click(this, e);
            }
        }
    }
}

Пример использования:

        <local:ImageButton x:Name="imgbutton"
                           NormalImage="C:/1.png"
                           DisabledImage="C:/2.png"
                           Click="ImgButton_Click"/>

(Обратите внимание, что текущее пространство имен Test, вы можете изменить это; Также я установил фиксированный размер на внутренней кнопке, которую вы, возможно, захотите удалить, просто не забудьте установить размер где-нибудь, так как я думаю, что он не будет использовать никаких пространство вообще, если вы этого не сделаете.)

person H.B.    schedule 13.02.2011
comment
Спасибо, я использовал Style вместо ControlTemplate и добавил несколько обработчиков OnXImagePropertyChanged в ваш код ImageSource, и, наконец, он заработал. На самом деле теперь я могу добавить свойство пути по умолчанию для папки изображений кнопок. - person JustAMartin; 13.02.2011
comment
@JustAMartin Как вы могли бы обработать событие изменения нового источника изображения, чтобы установить новое значение для вашего элемента управления? - person Dia; 21.05.2018
comment
@Dia Я раскопал наш старый код и создал Gist. В нем могут быть некоторые ошибки, потому что мне пришлось удалить некоторые части кода, относящиеся к проекту, но я думаю, что его следует использовать в качестве примера. gist.github.com/progmars/9d51e50fa03042264a83941e4f1e99c5 - person JustAMartin; 22.05.2018

Вот как я это вижу:

1) Создайте свой MyImageButton класс, который должен наследовать обычный Button и включать два свойства зависимости - NormalImage и DisabledImage. Эти свойства должны быть ImageSource типа. См. Здесь, как определить свойства зависимости: http://msdn.microsoft.com/en-us/library/ms752914.aspx#back_dependency_properties

2) Измените свой стиль на стиль для MyImageButton:

<ControlTemplate x:Key="ButtonTemplate" TargetType="{x:Type MyControls:MyImageButton}">

3) Измените ImageBrush в своем стиле как для включенного, так и для выключенного режима, чтобы использовать TemplateBinding. Вот так должно быть для включенного режима:

<ImageBrush ImageSource="{TemplateBinding NormalImage}"  />
person Snowbear    schedule 13.02.2011
comment
Спасибо, это полезно. Но могу ли я использовать NormalImage / DisabledImage в виде простых строк, чтобы упростить использование MyImageButton? - person JustAMartin; 13.02.2011
comment
Не уверен, сработает это или нет. Также это упростит использование только из кода программной части (не из XAML), потому что в XAML строка будет прозрачно преобразована в ImageSource. Кроме того, использование ImageSource, похоже, выровнено с WPF - строки не используются для таких свойств в WPF. - person Snowbear; 13.02.2011
comment
Причина, по которой я хотел бы использовать строки, заключается в том, чтобы избежать использования везде полного пути, поэтому я могу просто поместить enabledimage.png вместо pack: // application: ,,, / Resources / enabledimage.png, а WPF не добавляет пакет : // приложение автоматически для меня. - person JustAMartin; 13.02.2011

Взгляните на greyableimage.codeplex.com

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

person Peregrine    schedule 10.10.2011