将画布调整为相邻标签的文本高度

时间:2014-03-23 22:54:27

标签: c# wpf user-controls

对于WPF界面,我构建用户控件,在标签旁边显示一个图标。我在Canvas元素中构建图标,并将其粘贴在Label旁边的DockPanel中。我将其捆绑到UserControl中,以便整个控件可以绑定到单个值并重绘图标并在文本更改时更新文本(想想电池计量表)。

我无法将图标的画布缩放到与标签文本大致相同的高度,并将其大致定位在标签的基线上。是否有简单的方法吗?如果我允许通过属性更改字体怎么样呢,我可以检查布局测量并相应地缩放/定位图标的画布吗?

作为参考,这里是电池表的XAML,以及时钟和电池表的图像。请注意,电池表有点接近我想要的(在基线上,但不是文本的高度),但时钟太大。

<UserControl x:Class="Controls.Battery"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:controls="clr-namespace:Controls"
         x:Name="Root"
         mc:Ignorable="d" 
         d:DesignHeight="200" d:DesignWidth="900">
<DockPanel DataContext="{Binding ElementName=Root}" LastChildFill="True" Height="200" Width="900">
    <Canvas DockPanel.Dock="Left" Width="200" Height="200" Background="Transparent">
        <Rectangle Width="180" Height="100" StrokeThickness="20" Canvas.Top="50" Stroke="White" RadiusX="5" RadiusY="5">
            <Rectangle.Fill>
                <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                    <GradientStop Color="White" Offset="0"/>
                    <GradientStop Color="White" Offset="{Binding Percent}"/>
                    <GradientStop Color="Transparent" Offset="1"/>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>
        <Rectangle Width="40" Height="50" StrokeThickness="20" Canvas.Top="75" Canvas.Right="0" Stroke="White" RadiusX="5" RadiusY="5"/>
    </Canvas>

    <Viewbox HorizontalAlignment="Left">
        <TextBlock Text="{Binding Percent, Converter={controls:PercentConverter}}" Foreground="White" />
    </Viewbox>
</DockPanel>

Canvas/Label DockPanel

3 个答案:

答案 0 :(得分:2)

Canvas的子元素永远不会调整大小,它们只是位于指定的坐标位置。因此,改变画布的大小不会影响它的孩子。此外,Canvas的子元素总是具有他们想要的完整大小。因此,在您的情况下,我认为最好使用Grid元素。 这样的事情:

<UserControl x:Class="Controls.Battery"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:controls="clr-namespace:Controls"
     x:Name="Root"
     mc:Ignorable="d" 
     d:DesignHeight="200" d:DesignWidth="900">
<Grid DataContext="{Binding ElementName=Root}">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <Viewbox Grid.Column="0"
             VerticalAlignment="Center"
             Stretch="Uniform"
             StretchDirection="Both">
        <Grid Margin="10 60 10 40">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="Auto" />
            </Grid.ColumnDefinitions>
            <Rectangle Grid.Column="0"
                       Width="180"
                       Height="100"
                       RadiusX="5"
                       RadiusY="5"
                       Stroke="White"
                       StrokeThickness="20">
                <Rectangle.Fill>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="1,0">
                        <GradientStop Offset="0" Color="White" />
                        <GradientStop Offset="{Binding Percent}" Color="White" />
                        <GradientStop Offset="1" Color="Transparent" />
                    </LinearGradientBrush>
                </Rectangle.Fill>
            </Rectangle>
            <Rectangle Grid.Column="1"
                       Width="40"
                       Height="50"
                       Margin="-20 0 0 0"
                       RadiusX="5"
                       RadiusY="5"
                       Stroke="White"
                       StrokeThickness="20" />
        </Grid>
    </Viewbox>

    <Viewbox Grid.Column="1"
             HorizontalAlignment="Left"
             VerticalAlignment="Center">
        <TextBlock Foreground="White" Text="{Binding Percent, Converter={controls:PercentConverter}}" />
    </Viewbox>
</Grid>

答案 1 :(得分:1)

这是我能找到最接近解决方案的。我将TextBlock移动到画布内并用ViewBox包装以缩放整个批次,并在TextBlock周围放置一个ViewBox以缩放它以匹配画布高度。我还将画布高度更改为100(以消除电池上方和下方的空间),并对矩形进行了几次定位调整: -

        <Viewbox Stretch="Uniform"
                 StretchDirection="Both">
            <Canvas DockPanel.Dock="Left"
                    Width="400"
                    Height="100"
                    Background="Black">
                <Rectangle Width="180"
                           Height="100"
                           StrokeThickness="20"
                           Canvas.Top="0"
                           Stroke="White"
                           RadiusX="5"
                           RadiusY="5">
                    <Rectangle.Fill>
                        <LinearGradientBrush StartPoint="0,0"
                                             EndPoint="1,0">
                            <GradientStop Color="White"
                                          Offset="0" />
                            <GradientStop Color="White"
                                          Offset="{Binding Percent}" />
                            <GradientStop Color="Transparent"
                                          Offset="1" />
                        </LinearGradientBrush>
                    </Rectangle.Fill>
                </Rectangle>
                <Rectangle Width="40"
                           Height="50"
                           StrokeThickness="20"
                           Canvas.Top="25"
                           Canvas.Right="200"
                           Stroke="White"
                           RadiusX="5"
                           RadiusY="5" />

                <Viewbox Stretch="UniformToFill"
                         StretchDirection="Both"
                         Canvas.Left="200"
                         Height="100">
                    <TextBlock Text="1%"
                               Padding="0"
                               Margin="0"
                               LineStackingStrategy="BlockLineHeight"
                               LineHeight="20"
                               FontSize="20"
                               Foreground="White" />
                </Viewbox>
            </Canvas>
        </Viewbox>

将其放入一个窗口 - 你会发现画布和文本在调整窗口大小时会相互成比例(并保持其宽高比)。

电池没有与文本的顶部和底部完全对齐,但我怀疑是因为字体本身存在间距。我发现我可以通过在TextBlock上使用负顶部和底部边距来改善事物,但这可能是“hacky”,因为调整量取决于所使用的字体。

可能有更优雅的解决方案,例如使用几何/路径代替电池图标。 BTW你见过优秀的“Metro Studio”工具吗?这是一个免费的XAML图标集合 - 那里有几个电池,你可以根据自己的需要调整它们。

答案 2 :(得分:0)

您不应在xaml中使用精确像素值,而应绑定这些值并使用转换器设置正确的值。 (至少这是我要做的......)

所以命名你的TextBlock:

<Viewbox HorizontalAlignment="Left">
    <TextBlock x:Name="textPart" Text="{Binding Percent, Converter={controls:PercentConverter}}" Foreground="White" />
</Viewbox>

之后,您可以绑定到该属性的ActualWidthActualHeight属性。

例如:

<Canvas DockPanel.Dock="Left" 
        Width="200" 
        Height="{Binding Path=ActualHeight, ElementName=textPart}" 
        Background="Transparent">
...

为了进一步改善外观,你应该引入转换器,这样你就可以将宽度设置为给定的高度百分比,或者你想要的任何东西。

此外,您可以在画布中引入ScaleTransform,这很可能会减少对转换器的需求,因为您可以设计一个尺寸的“图片”,并且只需修改ScaleTansform即可大小合适。