SpacePurr
@SpacePurr
c#, wpf

Как изменить фон у button по Click при реализованном новом шаблоне?

Здравствуйте, комрады.

Я столкнулся с проблемой, которую долго не могу решить и не получается найти подробную информацию по этому вопросу.

У меня есть xaml с одной реализованной кнопкой.

Кнопка имеет градиентный фон LinearGradienBrush.
Триггер на событие IsPressed, в котором она меняет свой фон на радиальный градиент RadialGradientBrush, пока нажата.
Триггер на событие MouseEnter, в котором реализована зацикленная анимация на смену градиента фона в течение одной секунды при наведении указателя мыши на кнопку.
Триггер на событие MouseLeave, в котором реализован возврат к начальным значениям линейного градиента в течение одной секунды при выходе из области кнопки указателя мыши.
У кнопки реализован метод Click="AesButton_Click".

Задача состоит в том, чтобы поменять базовые цвета градиентов при нажатии на кнопку. Нажав второй раз, цвета должны вернутся к тем, которые были при запуске программы.
Я смог частично решить эту проблему через button.Template.FindName, но цвет остается только пока указатель находится в области кнопки.
Я думаю, что мне нужно добиться смены изначальных значений Color x:Key в .xaml через метод в .cs, но я могу ошибаться, потому как имею всего двухнедельный опыт в C#.

Спасибо.

<Window x:Class="SxApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SxApp"
        mc:Ignorable="d"
        Title="Aesthetic" Height="450" Width="450">


    <Window.Background>
        <ImageBrush 
            ImageSource="/SxApp;component/images/bck.jpg" Stretch="UniformToFill"/>
    </Window.Background>


    <Window.Resources>
        <Color x:Key="vapor_1">#db2525</Color>
        <Color x:Key="vapor_2">#a944ff</Color>
        <Color x:Key="vaporBorder">#8c5791</Color>
        <Color x:Key="vaporLime">#32CD32</Color>
        
        
        <ControlTemplate x:Key="ButtonTemplate"
                         TargetType="Button">
            <Border x:Name="Border"
                    CornerRadius="2000" 
                    TextBlock.Foreground="pink"
                    TextBlock.FontSize="23"
                    TextBlock.FontStyle="Italic"
                    TextBlock.FontWeight="Bold"
                    Margin="10"
                    >
                <Border.Background >
                    <LinearGradientBrush>
                        <GradientStopCollection>
                            <GradientStop Offset="0" Color="{StaticResource vapor_1}"/>
                            <GradientStop Offset="1" Color="{StaticResource vapor_2}"/>
                        </GradientStopCollection>
                    </LinearGradientBrush>
                </Border.Background>

                <ContentPresenter
                    RecognizesAccessKey="True"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center"
                    />
            </Border>

            <ControlTemplate.Triggers>

                <Trigger Property="IsPressed" Value="True">
                    <Setter TargetName="Border" Property="Background">
                        <Setter.Value>
                            <RadialGradientBrush>
                                <GradientStop Color="{StaticResource vaporBorder}" Offset="1" />
                                <GradientStop Color="{StaticResource vaporLime}" Offset="0.2" />
                            </RadialGradientBrush>
                        </Setter.Value>
                        
                    </Setter>
                </Trigger>

                <EventTrigger RoutedEvent="MouseEnter">
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty=
                                                            "Background.GradientStops[0].Color" 
                                            To="{StaticResource vapor_2}" Duration="0:0:1"
                                            AutoReverse="True"
                                            RepeatBehavior="Forever">

                            </ColorAnimation>

                            <ColorAnimation Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty=
                                                            "Background.GradientStops[1].Color" 
                                            To="{StaticResource vapor_1}" Duration="0:0:1"
                                            AutoReverse="True"
                                            RepeatBehavior="Forever">

                            </ColorAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>

                <EventTrigger RoutedEvent="MouseLeave">
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty=
                                                            "Background.GradientStops[0].Color" 
                                            To="{StaticResource vapor_1}" Duration="0:0:1">
                            </ColorAnimation>

                            <ColorAnimation Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty=
                                                            "Background.GradientStops[1].Color" 
                                            To="{StaticResource vapor_2}" Duration="0:0:1">
                            </ColorAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Window.Resources>
    
    
    <Grid>
        <Button
            Name="aesButton"
            Click="AesButton_Click"
            Content="Aesthetic"
            Width="200"
            Height="200"
            Template="{StaticResource ButtonTemplate}"/>
    </Grid>
</Window>


using System;
using System.Windows;

namespace SxApp
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void AesButton_Click(object sender, RoutedEventArgs e)
        {
            
        }
    }
}
  • Вопрос задан
  • 5233 просмотра
Решения вопроса 2
WNeZRoS
@WNeZRoS
Чтобы button.Background = Brushes.Red; работал нужно в ControlTemplate для Border'a вместо фиксированного цвета/градиента использовать биндинг на фон кнопки:
{TemplateBinding Background}

Но при этом в IsPressed триггере всё ещё останется фиксированный цвет, чтобы его тоже можно было менять нужно найти или создать (attached) DependencyProperty у кнопки куда этот цвет можно забиндить.
Так же в триггерах не работает TemplateBinding, вместо него следует использовать такой биндинг:
{Binding RelativeSource={RelativeSource TemplatedParent}, Path=PressedBackground}
Ответ написан
SpacePurr
@SpacePurr Автор вопроса
c#, wpf
Вопрос решен использованием {Binding MyVarName} и реализацией MyVarName переменной в Code Behind с реализованным интерфейсом INotifyPropertyChanged .
Binding работает как в Border так и в Trigger.
Все изменяется динамически в процессе работы программы (написал тестовое окно с двум полями, куда вводил HEX цвет, все отлично работает).
Binding не работает в ColorAnimation. Для передачи цвета в анимацию, аргумент должен быть "замороженным". Однако эта проблема также решаема созданием своего класса Button, наследуемого от FrameworkElement, но для меня это пока дебри.

Итого:
1. Реализация линейного градиента
2. Реализация градиентной зацикленной анимации при наведении
3. Реализация радиальной заливки при нажатии
4. Динамическая смена цвета градиента

XAML:
<Window x:Class="SxApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:SxApp"
        mc:Ignorable="d"
        Title="Aesthetic" Height="450" Width="450">


    <Window.Background>
        <ImageBrush 
            ImageSource="/SxApp;component/images/bck.jpg" Stretch="UniformToFill"/>
    </Window.Background>


    <Window.Resources>
        <Color x:Key="vapor_1">#db2525</Color>
        <Color x:Key="vapor_2">#a944ff</Color>
        <Color x:Key="vaporBorder">#8c5791</Color>
        <Color x:Key="vaporLime">#32CD32</Color>
        
        
        <ControlTemplate x:Key="ButtonTemplate"
                         TargetType="Button">
            <Border x:Name="Border"
                    CornerRadius="2000" 
                    TextBlock.Foreground="pink"
                    TextBlock.FontSize="23"
                    TextBlock.FontStyle="Italic"
                    TextBlock.FontWeight="Bold"
                    Margin="10"
                    >
                <Border.Background >
                    <LinearGradientBrush>
                        <GradientStopCollection>
                            <GradientStop Offset="0" Color="{Binding ButtonColor1}"/>
                            <GradientStop Offset="1" Color="{Binding ButtonColor2}"/>
                        </GradientStopCollection>
                    </LinearGradientBrush>
                </Border.Background>

                <ContentPresenter
                    RecognizesAccessKey="True"
                    VerticalAlignment="Center"
                    HorizontalAlignment="Center"
                    />
            </Border>

            <ControlTemplate.Triggers>
                <Trigger Property="IsPressed" Value="True">
                    <Setter TargetName="Border" Property="Background">
                        <Setter.Value>
                            <RadialGradientBrush>
                                <GradientStop Color="{Binding ButtonPressColor1}" Offset="1" />
                                <GradientStop Color="{Binding ButtonPressColor2}" Offset="0.2" />
                            </RadialGradientBrush>
                        </Setter.Value>
                    </Setter>
                </Trigger>

                <EventTrigger RoutedEvent="MouseEnter">
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty=
                                            "Background.GradientStops[0].Color" 
                                            To="{StaticResource vapor_2}" Duration="0:0:1"
                                            AutoReverse="True"
                                            RepeatBehavior="Forever">
                            </ColorAnimation>

                            <ColorAnimation Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty="Background.GradientStops[1].Color" 
                                            To="{StaticResource vapor_1}" Duration="0:0:1"
                                            AutoReverse="True"
                                            RepeatBehavior="Forever">
                            </ColorAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>

                <EventTrigger RoutedEvent="MouseLeave">
                    <BeginStoryboard>
                        <Storyboard>
                            <ColorAnimation Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty="Background.GradientStops[0].Color" 
                                            Duration="0:0:1">
                            </ColorAnimation>

                            <ColorAnimation Storyboard.TargetName="Border"
                                            Storyboard.TargetProperty="Background.GradientStops[1].Color" 
                                            Duration="0:0:1">
                            </ColorAnimation>
                        </Storyboard>
                    </BeginStoryboard>
                </EventTrigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Window.Resources>
    
    
    <Grid>
        <Button
            Name="aesButton"
            Click="AesButton_Click"
            Content="Aesthetic"
            Width="200"
            Height="200"
            Template="{StaticResource ButtonTemplate}"/>
    </Grid>
</Window>


C#:
using System;
using System.ComponentModel;
using System.Windows;

namespace SxApp
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        private string buttonColor1;
        public string ButtonColor1
        {
            get => buttonColor1;
            set
            {
                buttonColor1 = value;
                OnPropertyChanged("ButtonColor1");
            }
        }

        private string buttonColor2;
        public string ButtonColor2
        {
            get => buttonColor2;
            set
            {
                buttonColor2 = value;
                OnPropertyChanged("ButtonColor2");
            }
        }

        private string buttonPressColor1;
        public string ButtonPressColor1
        {
            get => buttonPressColor1;
            set
            {
                buttonPressColor1 = value;
                OnPropertyChanged("ButtonPressColor1");
            }
        }

        private string buttonPressColor2;
        public string ButtonPressColor2
        {
            get => buttonPressColor2;
            set
            {
                buttonPressColor2 = value;
                OnPropertyChanged("ButtonPressColor2");
            }
        }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            ButtonColor1 = "#db2525";
            ButtonColor2 = "#a944ff";
            ButtonPressColor1 = "#8c5791";
            ButtonPressColor2 = "#32CD32";
        }

        private void AesButton_Click(object sender, RoutedEventArgs e)
        {
            string temp = ButtonColor1;
            ButtonColor1 = ButtonColor2;
            ButtonColor2 = temp;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


5c5c52d0ec636963645101.png

Для реализации динамической смены цвета в анимации советовали почитать главу "Рисованные элементы" и "Создание элемента управления лишенного внешнего вида" в книге "Мэтью Мак-Дональд. WPF: Windows Presentation Foundation в .NET 4.0 с примерами на C# 2010 для профессионалов".
Всем большое спасибо.
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы