使用模糊效果让玻璃上的标签/文本块更易读

7

我正在使用 WPF 3.5 SP1,想要实现类似这样的效果(玻璃部分已经完成):


(来源:ggpht.com

源代码


源代码

您可以看到文本周围有一个漂亮的模糊效果,这使得它非常易读。我还发现使用API DrawThemeTextEx 是正确的方法,它使用推荐的系统选项来呈现模糊效果。然而,我该如何在WPF中实现相同的效果呢?
我能够找到以下链接,其中包含有用的资源:
如何使Aero玻璃背景上的WPF文本可读?
在玻璃表面上发光的标签控件 他们通过复制TextBlock并在其上设置模糊效果来实现此目的。然而,这不是一个真正的解决方案。以下是它的外观:

与上面的图片比较效果,你会发现解决方案还远远不够。那么我该如何使用WPF正确地获得所需的效果呢?只要结果非常相似,我就可以使用模拟(不使用DrawThemeTextEx API)。谢谢。
4个回答

7

根据Luke的要求,我包含了DecoratorXAML

<Decorator>
    <Decorator.Effect>
        <DropShadowEffect BlurRadius="7" Color="White" ShadowDepth="0" />
    </Decorator.Effect>
    <Decorator>
        <Decorator.Effect>
            <DropShadowEffect BlurRadius="7" Color="White" ShadowDepth="0" />
        </Decorator.Effect>
        <Decorator>
            <Decorator.Effect>
                <DropShadowEffect BlurRadius="7" Color="White" ShadowDepth="0" />
            </Decorator.Effect>

            <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}"
                    Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" 
                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" 
                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
        </Decorator>
    </Decorator>
</Decorator>

我使用上述的XAML为Label创建了一个ControlTemplate,并在需要文字发光的地方随处使用它。


我扩展了这个答案,以展示当禁用类别标签时,标签在外观上如何变暗,并可随时使用:https://dev59.com/ilTTa4cB1Zd3GeqPqj-S#21767564 - Triynko

7
    <TextBlock ...>
        <TextBlock.Effect>
            <DropShadowEffect BlurRadius="10" Color="White" ShadowDepth="0" />
        </TextBlock.Effect>
    </TextBlock>

谢谢,这是正确的方法。在最终解决方案中,我使用了3个嵌套的装饰器,其中包括DropShadowEffect和带有BlurEffect的克隆TextBlock,结果非常令人印象深刻。 - Paya
Paja,请问您能否提供一下如何嵌套DropShadowEffect的答案吗?我不太了解Decorator,因此不确定如何在TextBlock中实现。 - Luke
@Luke:根据您的要求,已在此处发布了答案链接 - Paya

2

这种做法是在文本背后加一个稍微模糊的矩形,我已经用过几次了。我觉得这样做可以增加可读性,因为模糊的区域更大。

            <Grid>
                <Rectangle Fill="#8FFFFFFF"
                           Stroke="{x:Null}"
                           StrokeThickness="0"
                           VerticalAlignment="Center"
                           Width="{Binding ActualWidth, ElementName=PART_Title, Mode=Default}"
                           Height="{Binding ActualHeight, ElementName=PART_Title, Mode=Default}"
                           RadiusX="2"
                           RadiusY="2">
                    <Rectangle.Effect>
                        <BlurEffect Radius="10" />
                    </Rectangle.Effect>
                </Rectangle>

                <TextBlock x:Name="PART_Title"
                           Text="{Binding Title}"
                           Foreground="Black"
                           TextWrapping="NoWrap"
                           TextTrimming="CharacterEllipsis" />
            </Grid>

嗯,那个方法可以用,但我想尽可能地模拟操作系统的行为。也许堆叠50个模糊的TextBlock可以解决问题,但肯定有更好的方法。 - Paya

1
我在实现Paya答案中的装饰器时遇到了问题,因此我展示了如何将其包裹在一个完整的、可立即使用的样式资源中,可以应用于任何标签,这将显示玻璃效果,并在禁用时淡化标签并保留对齐、边框等。
<Style x:Key="GlassLabelStyle" TargetType="{x:Type Label}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Label}">
                <Border BorderBrush="{TemplateBinding BorderBrush}" 
                BorderThickness="{TemplateBinding BorderThickness}" 
                Background="{TemplateBinding Background}" 
                Padding="{TemplateBinding Padding}" SnapsToDevicePixels="True">
                    <Grid>
                        <Decorator>
                            <Decorator.Effect>
                                <DropShadowEffect BlurRadius="7" Color="White" ShadowDepth="0" />
                            </Decorator.Effect>
                            <Decorator>
                                <Decorator.Effect>
                                    <DropShadowEffect BlurRadius="7" Color="White" ShadowDepth="0" />
                                </Decorator.Effect>
                                <Decorator>
                                    <Decorator.Effect>
                                        <DropShadowEffect BlurRadius="7" Color="White" ShadowDepth="0" />
                                    </Decorator.Effect>
                                    <ContentPresenter ContentTemplate="{TemplateBinding ContentTemplate}" 
                    Content="{TemplateBinding Content}" ContentStringFormat="{TemplateBinding ContentStringFormat}" 
                    HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" 
                    SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                                    </ContentPresenter>
                                </Decorator>
                            </Decorator>
                        </Decorator>
                    </Grid>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        <Setter Property="Opacity" Value="0.5"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

如果样式在您的窗口或应用程序资源中,则可以像这样应用它:
<Label Style="{StaticResource GlassLabelStyle}"

顺便提一下,我遇到了一个与TextBox相关的问题,当控件被禁用时,你根本无法改变其背景颜色(它会一直恢复为白色),所以有人发现你必须覆盖整个模板!请参见(https://dev59.com/Z2865IYBdhLWcg3wkPaD#3752517)。因此,这里有一个可供使用的样式,将使文本框在禁用时半透明(在玻璃上看起来很棒),并在启用时将其背景设置为半透明白色,并具有更明显的边框:

<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#01000000" />
<SolidColorBrush x:Key="DisabledBorderBrush" Color="#40000000" />
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#88ffffff" />

<Style x:Key="TextBoxStyle" TargetType="{x:Type TextBox}">
    <Setter Property="Background" Value="#88ffffff"/>
    <Setter Property="BorderBrush" Value="Black"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="TextBox">
                <Border Name="Bd" BorderThickness="{TemplateBinding BorderThickness}" 
                                    BorderBrush="{TemplateBinding BorderBrush}" 
                                    Background="{TemplateBinding Background}" 
                                    SnapsToDevicePixels="true">
                    <ScrollViewer Name="PART_ContentHost" Background="{TemplateBinding Background}" 
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Value="{StaticResource DisabledBackgroundBrush}" Property="Background" />
                        <Setter Value="{StaticResource DisabledBorderBrush}" Property="BorderBrush"/>
                        <Setter Value="{StaticResource DisabledForegroundBrush}" Property="Foreground" />
                        <Setter TargetName="PART_ContentHost" Property="Background" Value="{StaticResource DisabledBackgroundBrush}"/>
                        <Setter TargetName="PART_ContentHost" Property="BorderBrush" Value="{StaticResource DisabledBackgroundBrush}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接