如何剪辑(隐藏)可变大小TextBlock的上半部分?

时间:2013-11-20 09:25:25

标签: wpf xaml dynamic textblock clip

背景

我有一个基本Clock CustomControl,其DateTime属性每秒更新一次。它的默认ControlTemplateAnalogClockFace CustomControl,但我也有一个DigitalClockFace CustomControl我可以设置为Template值以进行数字显示。

最近,我想我会冒险尝试制作一个FlipDownClockFace CustomControl,类似于老式时钟,数字被垂直分割一半并显示在卷上,可以转动和翻转下一个数字随着时间的推移。不幸的是,我几乎落在了第一道,第二道障碍。

问题:

为了稍微简化这个问题,我需要显示两个TextBlock,每个显示Text值的相反两半。我的意思是,一个应显示TextBlock.Text值的上半部分,另一个应显示TextBlock.Text值的下半部分。实际上,我可以剪辑(显示)TextBlock的上半部分,显示下半部分就是问题。

要清楚,我需要剪辑区域自动调整大小以适应TextBlock而不管FontSize值,所以我不能硬编码Height值。这个问题只与TextBlock的裁剪有关,我将在稍后对Transform Animation控件所需的所有FlipDownClockFace进行整理。

到目前为止我尝试了什么:

我设法发现我可以使用RenderedGeometry元素的Rectangle属性作为TextBlock.Clip值,因此我认为我可以弹出RectangleGrid的每一半中剪辑两个(重叠的)TextBlock。此示例显示重建错误的位置(DoubleDivisorConverter只是将数据绑定值(Height)除以ConverterParameter的值(在本例中为2.0)):

<Grid TextElement.FontSize="72">
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Grid.RowSpan="2" Name="FirstValueBottomTextBox" Text="23" 
Clip="{Binding RenderedGeometry, ElementName=FirstValueBottomClipRectangle}" 
VerticalAlignment="Center" HorizontalAlignment="Center" Background="LightBlue" />
    <Rectangle Name="FirstValueBottomClipRectangle" Grid.Row="1" Height="{Binding 
ActualHeight, ElementName=FirstValueBottomTextBox, Converter={StaticResource 
DoubleDivisorConverter}, ConverterParameter=2.0}" VerticalAlignment="Top" />
</Grid>

基本上我发现问题在于RenderedGeometry只使用Geometry的{​​{1}}而不是位置,所以这只是剪辑(显示)上半部分文本,无论Rectangle的实际位置如何。我找不到任何方法将剪辑区域移动到底部,只显示文本的下半部分。

在你建议之前,我也不能这样做,因为Rectangle属性不幸是Rect.Height

DependencyProperty

因此,如果有人知道如何实现这一目标,或者您需要更多信息,请告知我们。

2 个答案:

答案 0 :(得分:1)

是否需要使用Clip功能?或OpacityMask是一种选择吗?以下代码接近这样一个时钟:

<Grid VerticalAlignment="Center" HorizontalAlignment="Center" TextElement.FontSize="36">
    <Grid.Resources>
        <Style x:Key="UpperHalfStyle" TargetType="{x:Type TextBlock}">
            <Setter Property="Margin" Value="0"/>
            <Setter Property="OpacityMask">
                <Setter.Value>
                    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                        <GradientStop Offset="0.5" Color="White"/>
                        <GradientStop Offset="0.5" Color="Transparent"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
        <Style x:Key="LowerHalfStyle" TargetType="{x:Type TextBlock}">
            <Setter Property="Margin" Value="0,2,0,0"/>
            <Setter Property="OpacityMask">
                <Setter.Value>
                    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                        <GradientStop Offset="0.5" Color="Transparent"/>
                        <GradientStop Offset="0.5" Color="White"/>
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>

    <StackPanel Orientation="Horizontal">
        <Grid>
            <TextBlock Text="1" Style="{StaticResource UpperHalfStyle}"/>
            <TextBlock Text="1" Style="{StaticResource LowerHalfStyle}"/>
        </Grid>
        <Grid>
            <TextBlock Text="0" Style="{StaticResource UpperHalfStyle}"/>
            <TextBlock Text="0" Style="{StaticResource LowerHalfStyle}"/>
        </Grid>
        <TextBlock Text=":"/>
        <Grid>
            <TextBlock Text="3" Style="{StaticResource UpperHalfStyle}"/>
            <TextBlock Text="3" Style="{StaticResource LowerHalfStyle}"/>
        </Grid>
        <Grid>
            <TextBlock Text="7" Style="{StaticResource UpperHalfStyle}"/>
            <TextBlock Text="7" Style="{StaticResource LowerHalfStyle}"/>
        </Grid>
    </StackPanel>
</Grid>

我只是覆盖了两个TextBlock元素。第一个只在上半部分是不透明的,而第二个在下半部分只是不透明的。我还在下半部分添加了Margin,因此很明显它们是两个不同的元素。我不知道你的其余设计,但我想你会想要在数字周围添加边框。为此,您可能必须以某种方式限制元素的高度。否则,边框将围绕整个TextBlock,而不仅仅是可见部分。

答案 1 :(得分:0)

好的,所以我尝试了@ gehho的建议,它在大多数情况下运行良好。我构建了我的FlipDownClockFace控件,这一切都很漂亮。问题是我是一个完美主义者,我想让它看起来更逼真。我想从包含Border的{​​{1}}元素的角落中删除一些内容,但发现我无法使用TextBlock执行该操作。

所以我回到绘图板调查OpacityMask的可能性。最后,我找到了一个解决方案,使我能够使用自定义Clip绑定到用作Point形状的PathGeometry的{​​{1}}。 Clip使用Converter接收Converter的{​​{1}}和Width,并将其转换为Height,其边缘取决于Border MultiBinding。它非常冗长(许多代码),但它的工作原理。对于那些感兴趣的人,这里是一个精简版:

Point

虽然这是我最终实际使用的解决方案,但我会留下@gehho接受的答案。