覆盖自定义样式的属性

时间:2017-11-24 10:02:35

标签: wpf xaml button properties

我的Style适用于我的应用程序的所有按钮:

<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
    <Setter Property="Background" Value="Red" />
    <Setter Property="Foreground" Value="Black" />
    <Setter Property="FontSize" Value="16" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Grid>
                    <Ellipse x:Name="StatusButtonCircle" Stroke="Black" StrokeThickness="0" Fill="AliceBlue" Stretch="Uniform">
                        <Ellipse.Width>
                            <Binding ElementName="StatusButtonCircle" Path="ActualHeight"/>
                        </Ellipse.Width>
                    </Ellipse>
                    <Ellipse x:Name="StatusButtonCircleHighlight" Margin="4" Stroke="Black" StrokeThickness="2" Stretch="Uniform">
                        <Ellipse.Width>
                            <Binding ElementName="StatusButtonCircleHighlight" Path="ActualHeight"/>
                        </Ellipse.Width>
                    </Ellipse>
                    <ContentPresenter HorizontalAlignment="Center"  
                                    VerticalAlignment="Center"/>
                </Grid>

                <ControlTemplate.Triggers>
                    ... some Triggers here
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如何在XAML中更改属性(例如FontWeight,FontSize等)?我试过这个:

<Button FontWeight="Bold" FontSize="30" Foreground="Red">
</Button>

在设计师视图中,我看到了变化。但在运行期间,这些更改不会应用。

经过一番调查后,我还有一个Style for all TextBlock,如下所示:

<Style TargetType="{x:Type TextBlock}">
    <Setter Property="FontSize" Value="16" />
    <Setter Property="FontFamily" Value="Segoe UI Semibold" />
    <Setter Property="Foreground" Value="White" />
</Style>

此样式似乎会覆盖Button上使用的TextBlock。我仍然无法更改XAML中的文本属性。

如果我在空项目中使用上面的样式,那么它就是这样的:

enter image description here

在设计器中,应用更改,在运行期间应用TextBlock中的更改。如果我将一个x:Key分配给TextBlock,它可以正常工作。但是我必须手动将此样式分配给应用程序中使用的每个TextBlock。

2 个答案:

答案 0 :(得分:1)

您在wpf中遇到典型的样式继承问题。

控件在初始化时查找其样式。控件查找其样式的方式是在逻辑树中向上移动,并询问逻辑父级是否存在父级资源字典中存储的适当样式。

在您的情况下,您在按钮中使用ContentPresenter作为默认行为。并且它默认使用TextBlock来表示按钮中的文本。

因此,在初始化时,ContentPresenter会查找TextBlock样式并应用于在按钮中表示内容。

如果要限制ContentPresenter查找样式,则必须将空白样式绑定到内容展示器,以便它不会查找任何其他样式。

<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
            <Setter Property="Background" Value="Red" />
            <Setter Property="Foreground" Value="Black" />
            <Setter Property="FontSize" Value="16" />

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Ellipse x:Name="StatusButtonCircle" Stroke="Black" StrokeThickness="0" Fill="AliceBlue" Stretch="Uniform">
                                <Ellipse.Width>
                                    <Binding ElementName="StatusButtonCircle" Path="ActualHeight"/>
                                </Ellipse.Width>
                            </Ellipse>
                            <Ellipse x:Name="StatusButtonCircleHighlight" Margin="4" Stroke="Black" StrokeThickness="2" Stretch="Uniform">
                                <Ellipse.Width>
                                    <Binding ElementName="StatusButtonCircleHighlight" Path="ActualHeight"/>
                                </Ellipse.Width>
                            </Ellipse>
                            <ContentPresenter HorizontalAlignment="Center"  
                                    VerticalAlignment="Center">
                                <ContentPresenter.Resources>
                                    <Style TargetType="TextBlock" BasedOn="{x:Null}"/>
                                    <!--  Assigned Blank style here therefore it will not search for any further style-->
                                </ContentPresenter.Resources>
                            </ContentPresenter>
                        </Grid>


                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

答案 1 :(得分:0)

首先,要复制此问题,需要在Style中设置ResourceDictionary,然后将其添加到Application.Resources(精确TextBlock全局样式)。在例如Style内设置Window.Resources不会重现该问题。

Global TextBlock Style应用于由ConentPresenter

创建的TextBlock

正如问题中所提到的,问题是Style的全局(无密钥)TextBlock在{I}结束内容时应用于TextBlock创建的ContentPresenter显示是一个字符串。由于某些原因,在Style内定义Window.Resources时不会发生这种情况。事实证明,除此之外,还有“控件正在父母资源中寻找自己的风格”。

ControlTemplate是不是从Control类

派生的元素的边界

对于TextBlock中的Control(不是来自UIElement类,而是来自ControlTemplate),这意味着wpf 不会查找它隐含Style超出它是模板化的父级。因此,它不会在其父资源中查找隐式Style,它将应用Style中找到的应用程序级隐式Application.Resources

这是设计(如果你愿意,硬编码到FrameworkElement),原因正是为了防止像这样的问题。假设您正在创建一个特定的Button设计(就像您一样),并且您希望应用程序中的所有按钮都使用该设计,甚至是其他ControlTemplate中的按钮。好吧,他们可以Button来自Control。另一方面,您不希望所有使用TextBlock的控件呈现文本,以应用隐式TextBlock Style。您将使用ComboBoxLabel来解决相同的问题...因为他们都使用TextBlock,而不只是Button

所以结论是:不要为Style中的Control类派生的元素定义全局Application.Resources,除非您100%确定这是什么你想要(例如将其移至Window.Resources)。或者,引用我在MahApps.Metro UI库的源代码中找到的评论:“永远不要在App.xaml中为TextBlock创建默认样式!!!”。您可以使用某种解决方案为TextBlock Button ControlTemplate中的Label添加样式,但是您必须为ComboBoxnew_york_data <- geo.lookup(state = "NY", place = "New York") prep_data <- function(full_data){ output <- data.frame() for(row in 1:nrow(full_data)){ new_rows <- replicateCounty(full_data[row, ]) output <- plyr::rbind.fill(output, new_rows) } return(output) } replicateCounty <- function(row){ counties <- str_trim(unlist(str_split(row$county.name, ","))) output <- data.frame(state = row$state, state.name = row$state.name, county.name = counties, place = row$place, place.name = row$place.name) return(output) } prep_data(new_york_data) 执行此操作,等等......所以,就是不要。