WPF — кнопка путается между триггерами IsMouseOver и IsPressed

#wpf #xaml

#wpf #xaml

Вопрос:

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

Но когда я нажимаю на кнопку и удерживаю ее, если я помещаю мышь «точно» на край кнопки, она непрерывно переключается между IsMouseOver IsPressed триггерами и, и это как бы конфликтует между ними и не знает, в каком состоянии она находится прямо сейчас, и заставляет кнопку увеличиваться, а затемпостоянно уменьшается, так как я могу это исправить?

Это код XAML

     <Style x:Key="MyButton" TargetType="Button">
        <Setter Property="FontWeight" Value="SemiBold"/>
        <Setter Property="Padding" Value="0,0,0,2"/>
        <Setter Property="BorderThickness" Value="2"/>
        <Setter Property="BorderBrush" Value="#4767CF"/>
        <Setter Property="Margin" Value="8"/>
        <Setter Property="FontSize" Value="15"/>
        <Setter Property="Background" Value="#272C30"/>
        <Setter Property="Foreground" Value="#ADB5BD"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border Padding="{TemplateBinding Padding}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}">
                        <ContentPresenter HorizontalAlignment="Center"
                                          VerticalAlignment="Center"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Cursor" Value="Hand"/>
                            <Setter Property="FontSize" Value="16"/>
                            <Setter Property="Margin" Value="6"/>
                            <Setter Property="Background" Value="#2F3439"/>
                            <Setter Property="Button.Effect">
                                <Setter.Value>
                                    <DropShadowEffect Color="Black" Direction="310"
                                          ShadowDepth="18" BlurRadius="30" Opacity="0.2"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="FontSize" Value="14"/>
                            <Setter Property="Margin" Value="8"/>
                            <Setter Property="Background" Value="#272C30"/>
                            <Setter Property="Button.Effect">
                                <Setter.Value>
                                    <DropShadowEffect Opacity="0"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
 

Комментарии:

1. «это изменяет поле на предыдущее значение и становится меньше» — так что не делайте этого. Допускайте, чтобы на поле влияло только местоположение мыши (наведение курсора мыши), а не другой пользовательский ввод. Определение «нажатой» заключается в том, что мышь все еще находится над кнопкой после нажатия кнопки мыши. Ваш код намеренно приводит к тому, что этого не происходит. Это всего лишь вариант явно враждебного пользователю поведения при перемещении кнопки в совершенно другое место, когда пользователь пытается нажать на нее. Не пишите враждебный пользователю код, и проблема исчезнет.

2. Вы имеете в виду, что я даже не должен изменять размер кнопки?

3. Я не думаю, что существует фундаментальная проблема с увеличением размера при наведении курсора мыши на кнопку. Но тогда оставьте это так, пока мышь находится над кнопкой, даже если кнопка нажата. Тем не менее, да: вам, безусловно, следует подумать, разумно ли вообще изменять размер; в некоторых пользовательских интерфейсах такие вещи могут быть полезны, особенно когда кнопки на самом деле не похожи на кнопки, и вы хотите получить какую-то обратную связь типа «привет, пользователь, ты можешь нажать здесь». Но если это не применимо в вашей ситуации, возможно, полностью переосмыслите весь «волнистый пользовательский интерфейс».

Ответ №1:

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

В приведенном ниже коде я использую поля границы, а не саму кнопку, для изменения размера, и я также использовал FallbackValue, чтобы сделать размер кнопки 50×100, если он явно не задан. В противном случае это почти тот же код, что и в вопросе.

введите описание изображения здесь

XAML:

 <Window x:Class="WpfApp12.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:WpfApp12"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <SolidColorBrush x:Key="BackgroundColor" Color="White"/>
        <Style x:Key="MyButton" TargetType="Button">
            <Setter Property="FontWeight" Value="SemiBold"/>
            <Setter Property="Padding" Value="0,0,0,2"/>
            <Setter Property="BorderThickness" Value="2"/>
            <Setter Property="BorderBrush" Value="#4767CF"/>
            <Setter Property="Margin" Value="6"/>
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="Width" Value="{Binding Path=Width,FallbackValue=100}"/>
            <Setter Property="Height" Value="{Binding Path=Height,FallbackValue=50}"/>
            <Setter Property="Background" Value="#272C30"/>
            <Setter Property="Foreground" Value="#ADB5BD"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border x:Name="MyBorder" Margin="2"
                                Padding="{TemplateBinding Padding}"
                                BorderThickness="{TemplateBinding BorderThickness}"
                                Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}">
                            <ContentPresenter HorizontalAlignment="Center"
                                               VerticalAlignment="Center"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Cursor" Value="Hand"/>
                                <Setter Property="FontSize" Value="16"/>
                                <Setter Property="Margin" Value="0" TargetName="MyBorder"/>
                                <Setter Property="Background" Value="#2F3439"/>
                                <Setter Property="Button.Effect">
                                    <Setter.Value>
                                        <DropShadowEffect Color="Black" Direction="310"
                                          ShadowDepth="18" BlurRadius="30" Opacity="0.2"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="FontSize" Value="14"/>
                                <Setter Property="Margin" Value="2" TargetName="MyBorder"/>
                                <Setter Property="Background" Value="#272C30"/>
                                <Setter Property="Button.Effect">
                                    <Setter.Value>
                                        <DropShadowEffect Opacity="0"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <StackPanel>
        <TextBlock Background="{StaticResource BackgroundColor}"></TextBlock>
        <StackPanel Orientation="Horizontal">
            <TextBlock Background="{StaticResource BackgroundColor}" Width="100"></TextBlock>
            <Button x:Name="MyButton" Height="100" Width="200" Style="{StaticResource MyButton}">Button</Button>
            <TextBlock Background="{StaticResource BackgroundColor}" Width="700"></TextBlock>
        </StackPanel>
        <TextBlock Background="{StaticResource BackgroundColor}"></TextBlock>
    </StackPanel>
</Window>
 

Альтернативное решение

В качестве альтернативы вы можете увеличить размер кнопки при наведении курсора мыши, используя свойство RenderTransform, которое является более стандартным способом решения проблемы в WPF. Проблема в том, что, похоже, содержимое кнопки размывается гораздо сильнее, чем просто установка поля:

 <Window x:Class="WpfApp10.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:WpfApp10"
        mc:Ignorable="d"
        Title="MainWindow" Height="800" Width="800">
    <Window.Resources>
        <SolidColorBrush x:Key="BackgroundColor" Color="White"/>
        <Style x:Key="MyButton" TargetType="Button">
            <Setter Property="FontWeight" Value="SemiBold"/>
            <Setter Property="Padding" Value="0,0,0,2"/>
            <Setter Property="BorderThickness" Value="2"/>
            <Setter Property="BorderBrush" Value="#4767CF"/>
            <Setter Property="Margin" Value="8"/>
            <Setter Property="FontSize" Value="15"/>
            <Setter Property="Background" Value="#272C30"/>
            <Setter Property="Foreground" Value="#ADB5BD"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <Border Padding="{TemplateBinding Padding}"
                            BorderThickness="{TemplateBinding BorderThickness}"
                            Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}">
                            <ContentPresenter HorizontalAlignment="Center"
                                          VerticalAlignment="Center"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsMouseOver" Value="True">
                                <Setter Property="Cursor" Value="Hand"/>
                                <Setter Property="FontSize" Value="16"/>
                                <!--<Setter Property="Margin" Value="6"/>-->
                                <Setter Property="Background" Value="#2F3439"/>
                                <Setter Property="Button.Effect">
                                    <Setter.Value>
                                        <DropShadowEffect Color="Black" Direction="310"
                                          ShadowDepth="18" BlurRadius="30" Opacity="0.2"/>
                                    </Setter.Value>
                                </Setter>
                                <Setter Property="RenderTransformOrigin" Value="0.5, 0.5"/>
                                <Setter Property="RenderTransform">
                                    <Setter.Value>
                                        <ScaleTransform ScaleX="1.03" ScaleY="1.03"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                            <Trigger Property="IsPressed" Value="True">
                                <Setter Property="FontSize" Value="14"/>
                                <!--<Setter Property="Margin" Value="8"/>-->
                                <Setter Property="Background" Value="#272C30"/>
                                <Setter Property="Button.Effect">
                                    <Setter.Value>
                                        <DropShadowEffect Opacity="0"/>
                                    </Setter.Value>
                                </Setter>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
    <StackPanel>
        <TextBlock Background="{StaticResource BackgroundColor}"></TextBlock>
        <StackPanel Orientation="Horizontal">
            <TextBlock Background="{StaticResource BackgroundColor}" Width="100"></TextBlock>
            <Button x:Name="MyButton" Height="100" Width="200" Style="{StaticResource MyButton}">Button</Button>
            <TextBlock Background="{StaticResource BackgroundColor}" Width="700"></TextBlock>
        </StackPanel>
        <TextBlock Background="{StaticResource BackgroundColor}"></TextBlock>
    </StackPanel>
</Window>