以编程方式在 xaml 按钮上设置样式失败

Setting the style on a xaml button programmatically fails

我正在开发一个控件。此控件需要使用来自外部源的输入来设置样式。我一直在寻找解决方案并找到了一些没有破坏代码的解决方案。但是它没有为按钮设置样式。我将样式设置为资源。在按钮上应用对它的引用。初始化内容,但不应用样式。

     public MainPage()
    {

        //String[] settings = Application.Current.Resources["settings"].ToString().Split(new Char[1] { '\u003A' });

        String[] settings = "_icons/pngp/2933.png:1:ff0000:Select files from disk...:36:36".Split(new Char[1] { '\u003A' });

        //style the dialog button
        ImageBrush image = new ImageBrush();
        image.ImageSource = new BitmapImage(new Uri(settings[0], UriKind.Relative));
        Button dialogButton = new Button();

        dialogButton.Background = image;

        var styleOverride = new Style(typeof(Button)) ;
        styleOverride.Setters.Add(new Setter(Border.CornerRadiusProperty, new CornerRadius(0)));
        styleOverride.Setters.Add(new Setter(Border.BorderBrushProperty, colorConverter(settings[2])));
        styleOverride.Setters.Add(new Setter(Border.BorderThicknessProperty, new Thickness(double.Parse(settings[1]))));
        this.Resources.Add("key", styleOverride);

        dialogButton.Style = this.Resources["key"] as Style;
        dialogButton.Height = double.Parse(settings[4]);
        dialogButton.Width = double.Parse(settings[5]);
        //attach the click handler;
        dialogButton.Click += dialogButton_Click;

        ToolTip tooltip = new ToolTip();
        tooltip.Content = settings[3];

        ToolTipService.SetToolTip(dialogButton, tooltip);


        this.InitializeComponent();

        this.LayoutRoot.Children.Add(dialogButton);
        this.LayoutRoot.Drop += this.Canvas_Drop;
    }

我已经对 settings 字符串进行了硬编码。通常这是动态的并且来自外部资源。问题是为什么 dialogButton.Style = this.Resources["key"] as Style; 没有应用所需的样式效果?

图像显示了现在的结果(左)和期望的效果(右)。没有圆角边框和不同的 border-color。不,红色不会是最终的颜色。用于调试。

不要直接在代码后面设置Style:

dialogButton.Style = this.Resources["key"] as Style;

但使用 SetValue 方法:

var style = this.Resources["key"] as Style; // or this.TryFindResource("key") as Style;
dialogButton.SetValue(StyleProperty, style);

似乎应用了样式,但红色边框覆盖了 png。 尝试注释掉行:

/* styleOverride.Setters.Add(new Setter(Border.BorderBrushProperty, colorConverter(settings[2]))); */

现在可以看到背景图片了。 也许解决方案是将图像调整为 40x40 像素并留有边距?

您的代码中有两个问题。

首先,您使用的 Border.BorderBrushPropertyBorder.BorderThicknessProperty 不是 Button 控件中的依赖属性。您应该将它们分别更改为 Button.BorderBrushPropertyButton.BorderThicknessProperty,如下所示 -

styleOverride.Setters.Add(new Setter(Button.BorderBrushProperty, colorConverter(settings[2])));
styleOverride.Setters.Add(new Setter(Button.BorderThicknessProperty, new Thickness(double.Parse(settings[1]))));

第二个问题是 Button 控件中没有 CornerRadius 依赖项 属性。所以你不能简单地把它改成 Button.CornerRadiusProperty.

解决方法是,在你的页面中定义一个本地Button Style,然后使用TemplateBinding绑定BorderCornerRadius(在 ButtonControlTemplate 内)到 Tag 依赖项 属性。这部分在 xaml.

中更容易完成
CornerRadius="{TemplateBinding Tag}"

然后,您只需应用 Style 作为覆盖 StyleBaseOn 并更新 Tag 属性。

var styleOverride = new Style(typeof(Button))
{
    BasedOn = (Style)this.Resources["ButtonStyle1"]
};

styleOverride.Setters.Add(new Setter(Button.TagProperty, new CornerRadius(0)));

这里附上完整的xamlButtonStyle.

<Style x:Key="ButtonStyle1" TargetType="Button">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid>
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundAnimation"/>
                                    <ColorAnimation Duration="0" To="#F2FFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                                    <ColorAnimation Duration="0" To="#CCFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                                    <ColorAnimation Duration="0" To="#7FFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Pressed">
                                <Storyboard>
                                    <ColorAnimation Duration="0" To="#FF6DBDD1" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" Storyboard.TargetName="Background"/>
                                    <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundAnimation"/>
                                    <ColorAnimation Duration="0" To="#D8FFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                                    <ColorAnimation Duration="0" To="#C6FFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                                    <ColorAnimation Duration="0" To="#8CFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                                    <ColorAnimation Duration="0" To="#3FFFFFFF" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)" Storyboard.TargetName="BackgroundGradient"/>
                                </Storyboard>
                            </VisualState>
                            <VisualState x:Name="Disabled"/>
                        </VisualStateGroup>
                        <VisualStateGroup x:Name="FocusStates">
                            <VisualState x:Name="Focused"/>
                            <VisualState x:Name="Unfocused"/>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="Background" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="White" CornerRadius="{TemplateBinding Tag}">
                        <Grid Background="{TemplateBinding Background}" Margin="1" d:IsHidden="True">
                            <Border x:Name="BackgroundAnimation" Background="#FF448DCA" Opacity="0" d:IsHidden="True"/>
                            <Rectangle x:Name="BackgroundGradient" d:IsHidden="True">
                                <Rectangle.Fill>
                                    <LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0">
                                        <GradientStop Color="#FFFFFFFF" Offset="0"/>
                                        <GradientStop Color="#F9FFFFFF" Offset="0.375"/>
                                        <GradientStop Color="#E5FFFFFF" Offset="0.625"/>
                                        <GradientStop Color="#C6FFFFFF" Offset="1"/>
                                    </LinearGradientBrush>
                                </Rectangle.Fill>
                            </Rectangle>
                        </Grid>
                    </Border>
                    <ContentPresenter x:Name="contentPresenter" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" d:IsHidden="True"/>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

我测试了代码,结果正是你所期望的。

希望对您有所帮助!