我有一个基本Clock CustomControl
,其DateTime
属性每秒更新一次。它的默认ControlTemplate
是AnalogClockFace CustomControl
,但我也有一个DigitalClockFace CustomControl
我可以设置为Template
值以进行数字显示。
最近,我想我会冒险尝试制作一个FlipDownClockFace CustomControl
,类似于老式时钟,数字被垂直分割一半并显示在卷上,可以转动和翻转下一个数字随着时间的推移。不幸的是,我几乎落在了第一道,第二道障碍。
为了稍微简化这个问题,我需要显示两个TextBlock
,每个显示Text
值的相反两半。我的意思是,一个应显示TextBlock.Text
值的上半部分,另一个应显示TextBlock.Text
值的下半部分。实际上,我可以剪辑(显示)TextBlock
的上半部分,显示下半部分就是问题。
要清楚,我需要剪辑区域自动调整大小以适应TextBlock
而不管FontSize
值,所以我不能硬编码Height
值。这个问题只与TextBlock
的裁剪有关,我将在稍后对Transform Animation
控件所需的所有FlipDownClockFace
进行整理。
我设法发现我可以使用RenderedGeometry
元素的Rectangle
属性作为TextBlock.Clip
值,因此我认为我可以弹出Rectangle
在Grid
的每一半中剪辑两个(重叠的)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
因此,如果有人知道如何实现这一目标,或者您需要更多信息,请告知我们。
答案 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接受的答案。