自定义按钮上的 XAML UWP 焦点背景

Posted

技术标签:

【中文标题】自定义按钮上的 XAML UWP 焦点背景【英文标题】:XAML UWP focus background on custom button 【发布时间】:2018-03-07 16:46:55 【问题描述】:

在 XAML UWP 应用程序中,我有一个扩展 Button 的类。 我已经设置了背景 ImageBrush。

我的问题是,当我的按钮获得焦点或鼠标悬停事件时,我的按钮上会出现一个带有黑色边框的灰色矩形。

我已经尝试了 一大堆 解决方案,从更改前景到在各种事件(gotFocusmouseEnteredmouseover)上修改 FocusVisualPrimary/SecondaryBrush。 没有任何效果,我得到的最好结果是在mouseover 事件上设置button.Background = "originalBitmapImage"(我创建了一个与原始背景具有相同图像路径的新ImageBrush,然后将其归因于BackGround),但是当鼠标悬停时图像全部闪烁触发(因为它每次都重新加载一个新图像)。

这是显示问题的图片(左:普通按钮,右:鼠标悬停的相同按钮):

我想在这两种情况下保持相同的图像,我有点不知所措。

public class MyButton : Button 


private static string Image_path = "ms-appx:///assets/Button.png";

        public MyButton()
        

            ImageBrush brush = new ImageBrush()
            
                ImageSource = new BitmapImage(new Uri(MyButton.Image_path))
            ;
            this.Background = brush;

            this.PointerEntered += a;

        

        // This almost work, but the image is flickering when event is fired
        private void a(object sender, PointerRoutedEventArgs e)
        
            ImageBrush brush = new ImageBrush()
            
                ImageSource = new BitmapImage(new Uri(MyButton.Image_path))
            ;
            //this.Foreground = brush;
            this.Background = brush;
        

【问题讨论】:

如果您只想停止闪烁,请将这些图像保存在一些外部字段中。如果你想防止这种奇怪的行为,你可以创建模板,或者更容易使用 ContentControl 并将图像设置为内容,或者使用它的背景属性设置边框 【参考方案1】:

我们可以复制Button的默认样式,然后我们可以在Template中编辑VisualStatePointerOver

从默认样式开始,它将ButtonBackgroundPointerOver ThemeResource 设置为PointerOver VisualState 中Button 的Background。所以我们可以在页面资源中定义ButtonBackgroundPointerOver,而不需要修改Button的样式。

例如:

<Page.Resources>
    <StaticResource x:Key="ButtonBackground" ResourceKey="MyMyImageBrush" />
    <StaticResource x:Key="ButtonBackgroundPointerOver" ResourceKey="MyMyImageBrush" />
    <StaticResource x:Key="ButtonBackgroundPressed" ResourceKey="SystemControlBackgroundBaseMediumLowBrush" />
    <ImageBrush x:Key="MyMyImageBrush" ImageSource="ms-appx:///assets/Button.png" />
</Page.Resources>

【讨论】:

谢谢,我会在短时间内测试这个解决方案。万一,有没有办法在代码后面做到这一点?我的按钮此时是一个类,而不是 XAML 元素。 这是我目前得到的最佳解决方案,但这会修改​​页面上的所有按钮。问题是我可以有不止一种类型的按钮:所以我需要能够为不同类型的按钮设置不同的背景(即在我的情况下是不同的图像)。如果有一个解决方案可以直接在我的不同按钮类中的代码上实现,那将非常酷。谢谢【参考方案2】:

最后我找到了一个解决方案:我为项目的每个页面添加了 5 种类型的按钮样式。这不是一个很好的解决方案,因为按钮是从 c# 类(后面的代码)创建的,以便分解代码,并且所有样式都添加了 500+ 代码行,以便在鼠标悬停时进行简单的图像修改......

我使用了这种样式:

'

    <Style TargetType="local:MyButton">
        <!--<Setter Property="Background" Value="ThemeResource SystemControlBackgroundBaseLowBrush" />
        <Setter Property="Foreground" Value="ThemeResource SystemControlForegroundBaseHighBrush"/>
        <Setter Property="BorderBrush" Value="ThemeResource SystemControlForegroundTransparentBrush" />
        <Setter Property="BorderThickness" Value="ThemeResource ButtonBorderThemeThickness" />-->
        <Setter Property="Padding" Value="8,4,8,4" />
        <!--<Setter Property="HorizontalAlignment" Value="Left" />
        <Setter Property="VerticalAlignment" Value="Center" />
        <Setter Property="FontFamily" Value="ThemeResource ContentControlThemeFontFamily" />
        <Setter Property="FontWeight" Value="Normal" />
        <Setter Property="FontSize" Value="ThemeResource ControlContentThemeFontSize" />-->
        <Setter Property="UseSystemFocusVisuals" Value="True" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:MyButton">
                    <Grid x:Name="RootGrid" Background="TemplateBinding Background">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualState x:Name="Normal">
                                    <Storyboard>
                                        <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="PointerOver">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                               Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="ThemeResource SystemControlHighlightBaseMediumLowBrush" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                               Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="ThemeResource SystemControlHighlightBaseHighBrush" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <PointerUpThemeAnimation Storyboard.TargetName="RootGrid" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid"
                                               Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="ThemeResource SystemControlBackgroundBaseMediumLowBrush" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                               Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="ThemeResource SystemControlHighlightTransparentBrush" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                               Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="ThemeResource SystemControlHighlightBaseHighBrush" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <PointerDownThemeAnimation Storyboard.TargetName="RootGrid" />
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled">
                                    <Storyboard>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid"
                                               Storyboard.TargetProperty="Background">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="ThemeResource SystemControlBackgroundBaseLowBrush" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                               Storyboard.TargetProperty="Foreground">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="ThemeResource SystemControlDisabledBaseMediumLowBrush" />
                                        </ObjectAnimationUsingKeyFrames>
                                        <ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter"
                                               Storyboard.TargetProperty="BorderBrush">
                                            <DiscreteObjectKeyFrame KeyTime="0" Value="ThemeResource SystemControlDisabledTransparentBrush" />
                                        </ObjectAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ContentPresenter x:Name="ContentPresenter"
                      BorderBrush="TemplateBinding BorderBrush"
                      BorderThickness="TemplateBinding BorderThickness"
                      Content="TemplateBinding Content"
                      ContentTransitions="TemplateBinding ContentTransitions"
                      ContentTemplate="TemplateBinding ContentTemplate"
                      Padding="TemplateBinding Padding"
                      HorizontalContentAlignment="TemplateBinding HorizontalContentAlignment"
                      VerticalContentAlignment="TemplateBinding VerticalContentAlignment"
                      AutomationProperties.AccessibilityView="Raw"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</Page.Resources>'

【讨论】:

以上是关于自定义按钮上的 XAML UWP 焦点背景的主要内容,如果未能解决你的问题,请参考以下文章

uwp xaml - 将自定义输入格式设置为文本框

如何在 C# 中更改 UWP 应用程序中按钮的背景颜色?

UWP 自定义矩形形状

UWP 自定义密码框控件

自定义控制按钮 C# UWP

XAML: 自定义控件中事件处理的最佳实践