WPF以拉伸标签固定宽度为中心文本

时间:2022-11-10 15:10:57

My goal is simpel, however i can't figure it out. Sorry for the Titel but couldn't come up with a better explanation...

我的目标是简单,但我无法弄清楚。对不起标题,但无法提出更好的解释......

I have usercontrol with an label that display's the current time (hooked up to a timer with 1 second interval). The label is the width of its parent and the text is aligned in the center. The format is DateTime.ToString("HH : mm : ss"), the FontFamily and size can be adjusted by the user. So far nothing strange... But, the text is aligned centered so when time is lets say 12:34:02 the pixel width different than 12:34:11. (of course depending on the font) This causes the label jump (because it auto centers itself)

我有一个带有标签的usercontrol,显示当前时间(连接到1秒间隔的计时器)。标签是其父级的宽度,文本在中心对齐。格式为DateTime.ToString(“HH:mm:ss”),FontFamily和大小可由用户调整。到目前为止没有什么奇怪的......但是,文本对齐居中,所以当时间让我们说12:34:02像素宽度不同于12:34:11。 (当然取决于字体)这会导致标签跳转(因为它自动居中)

The code below is an example of it. the canvas is used to draw stuff on it and the viewbox is used so it autosizes itself in his parent.

下面的代码就是一个例子。画布用于在其上绘制内容并使用视图框,因此它会在其父级中自动进行自动调整。

Code:

码:

 <Grid>
    <Viewbox>
        <Canvas Name="canv" Height="300" Width="300">
            <StackPanel Name="stckpnlDateTime">

                <Label Name="lblDateOrText" 
                       Grid.Column="0"
                       Grid.Row="0"
                       Content = "------" 
                       FontSize="25"
                       Foreground="GhostWhite"
                       HorizontalContentAlignment="Center"
                       VerticalAlignment="Bottom"
                       FontFamily="Arial"
                       Width="Auto"/>

                <Label Name="lblTime"
                       Grid.Column="0"
                       Grid.Row="1"
                       Content = "-- : -- : --"
                       FontSize="25"
                       Foreground="GhostWhite"
                       HorizontalContentAlignment="Center"
                       VerticalAlignment="Top"
                       FontFamily="DS-Digital"
                       Width="Auto"/>
            </StackPanel>                
        </Canvas>
    </Viewbox>
</Grid>

Private Sub SystemTime_Tick(sender As Object, e As EventArgs) Handles tmrSystemTime.Tick
    lblTime.Content = Now.ToString("HH : mm : ss")
End Sub

So i tried a different approach, great a grid with 10 columns and 8 labels, one for each char, and stretch the labels to its parent (cell). This works and keeps the chars on a fixed position. But the width of last column is smaller then the rest... In this image you can see hat i mean, the second purple column is what i mean. Example alignment

所以我尝试了一种不同的方法,一个包含10列和8个标签的网格,每个字符一个,并将标签拉伸到其父级(单元格)。这样可以将字符保持在固定位置。但是最后一列的宽度比其余的要小......在这张图片中你可以看到帽子我的意思是,第二列是我的意思。示例对齐

Code:

码:

 <UserControl.Resources>
    <Style x:Key="LabelStyle" TargetType="Label">
        <Setter Property="Foreground" Value="White" />
        <Setter Property="FontFamily" Value="DS-Digital" />
        <Setter Property="FontSize" Value="40"/>
        <Setter Property="HorizontalAlignment" Value="Center"/>
        <Setter Property="HorizontalContentAlignment" Value="Right"/>
        <Setter Property="Background" Value="Green" />
    </Style>
</UserControl.Resources>

<Grid HorizontalAlignment="Stretch">
    <Viewbox HorizontalAlignment="Stretch">
        <Canvas Name="canv" Height="300" Width="300" HorizontalAlignment="Stretch">
            <StackPanel Name="stckpnlDateTime" HorizontalAlignment="Stretch">                    
                <Label Name="lblDateOrText" 
                       Grid.Column="0"
                       Grid.Row="0"
                       Content = "" 
                       FontSize="25"
                       Foreground="GhostWhite"
                       HorizontalContentAlignment="Center"
                       VerticalAlignment="Bottom"
                       FontFamily="Arial"
                       Width="Auto"/>

                <Grid Name="GridTimeLabel" HorizontalAlignment="Stretch"  Width="Auto" Grid.Column="0" Grid.Row="1">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="1*"/>
                    </Grid.ColumnDefinitions>


                    <Label Background="Purple" Grid.Column="0" Grid.Row="0"/>
                    <Label Name="lblTime1" Grid.Column="1" Grid.Row="0" Style="{StaticResource LabelStyle}" Content="-"/>
                    <Label Name="lblTime2" Grid.Column="2" Grid.Row="0" Style="{StaticResource LabelStyle}" Content="-"/>
                    <Label Name="lblTime3" Grid.Column="3" Grid.Row="0" Style="{StaticResource LabelStyle}" Content=":"/>
                    <Label Name="lblTime4" Grid.Column="4" Grid.Row="0" Style="{StaticResource LabelStyle}" Content="-"/>
                    <Label Name="lblTime5" Grid.Column="5" Grid.Row="0" Style="{StaticResource LabelStyle}" Content="-"/>
                    <Label Name="lblTime6" Grid.Column="6" Grid.Row="0" Style="{StaticResource LabelStyle}" Content=":"/>
                    <Label Name="lblTime7" Grid.Column="7" Grid.Row="0" Style="{StaticResource LabelStyle}" Content="-"/>
                    <Label Name="lblTime8" Grid.Column="8" Grid.Row="0" Style="{StaticResource LabelStyle}" Content="-"/>
                    <Label Background="Purple" Grid.Column="9" Grid.Row="0"/>
                </Grid>                 
            </StackPanel>                
        </Canvas>
    </Viewbox>
</Grid>

Long story short, i'm stuk.... hopefully someone could point me in the right direction.

长话短说,我是stuk ....希望有人可以指出我正确的方向。

3 个解决方案

#1


0  

I have two methods in mind.

我有两种方法。

First method: Change to a monospace font, this will ensure that no matter what time value you throw at it, the width will be constant. But you may not find a good/suitable font using this method, though.

第一种方法:改为等宽字体,这将确保无论你抛出什么时间值,宽度都是恒定的。但是,您可能无法使用此方法找到合适/合适的字体。

Second method: If you are not using MVVM, try this (C# code, I'm not too used to VB.net):

第二种方法:如果你没有使用MVVM,试试这个(C#代码,我不太习惯VB.net):

// Code-behind
public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    var label = this.lblTime;
    label.Text = "00:00:00";
    label.Measure(); // Force it to measure
    label.Width = label.DesiredSize.Width;
}

This will force the width to stay constant. Depending on the font, you need to manually set the time value that takes up the most space.

这将迫使宽度保持不变。根据字体的不同,您需要手动设置占用最多空间的时间值。

Also, to be sure it works properly, you may need to wrap the Label in a Grid. Make the Grid have 3 columns, set the label in column 1 (middle column), and set the columndefinitions' widths to *, auto and * respectively in that order.

此外,为了确保它正常工作,您可能需要将Label包装在网格中。使网格有3列,在第1列(中间列)中设置标签,并将columndefinitions的宽度分别按顺序设置为*,auto和*。

#2


0  

Your Canvas has a width of 300. It looks to me as there is less than 300 px available. This is why the last column is smaller.

你的画布宽度为300.它对我来说,因为可用的不到300像素。这就是最后一栏较小的原因。

#3


0  

@Jai, thanks for pointing me in the direction of the .Measure() Sub. After fiddling around i ended up with the 3 column grid, measuring the size of the label with the new content, setting the size of the label. This causes the Column to realign, which holds the label in place.

@Jai,谢谢你指点我.Measure()Sub的方向。摆弄后我最终得到3列网格,用新内容测量标签的大小,设置标签的大小。这会导致Column重新对齐,从而将标签保持在原位。

The code: (created new WPF program for the test, The colors are to see the difference between child and parent)

代码:(为测试创建新的WPF程序,颜色是看孩子和父母之间的区别)

    <Grid Background="Tomato">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Label Name="lblTime"
                   Grid.Column="1"
                   Grid.Row="0"
                   Content = "-- : -- : --"
                   FontSize="50"
                   Foreground="Black"
                   Background="Beige"
                   HorizontalContentAlignment="Left"
                   VerticalAlignment="Center"
                   FontFamily="DS-Digital"/>
</Grid>

And the code behind it:

它背后的代码:

Class MainWindow

MainWindow类

''' <summary>
''' Timer for updating the time Clock
''' </summary>
Dim WithEvents tmrSystemTime As New DispatcherTimer With {.Interval = TimeSpan.FromSeconds(1)} 'Set Timer interval on every second.

Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    tmrSystemTime.Start()
End Sub

Private Sub SystemTime_Tick(sender As Object, e As EventArgs) Handles tmrSystemTime.Tick
    'Set the time in the label
    lblTime.Content = Now.ToString("HH : mm : ss")

    'Measure and set the size of the label
    MeasureSizeTimeLabel()
End Sub

''' <summary>
''' Measure the Max Size of the label with a specific Format
''' </summary>
Private Sub MeasureSizeTimeLabel()

    'Store the Max size of the Time Label in this variable
    Dim MaxClockSize As Size

    'Measure the Max size of the clock label and use this width
    'lblTime.Content = "00 : 00 : 00"
    lblTime.Measure(New Size(Double.PositiveInfinity, Double.PositiveInfinity))
    MaxClockSize = lblTime.DesiredSize

    'Now Set the size of the label
    lblTime.Width = MaxClockSize.Width
    lblTime.Height = MaxClockSize.Height
End Sub

Thanks all for the help, appreciate the effort and time! :-)

感谢大家的帮助,感谢您的努力和时间! :-)

#1


0  

I have two methods in mind.

我有两种方法。

First method: Change to a monospace font, this will ensure that no matter what time value you throw at it, the width will be constant. But you may not find a good/suitable font using this method, though.

第一种方法:改为等宽字体,这将确保无论你抛出什么时间值,宽度都是恒定的。但是,您可能无法使用此方法找到合适/合适的字体。

Second method: If you are not using MVVM, try this (C# code, I'm not too used to VB.net):

第二种方法:如果你没有使用MVVM,试试这个(C#代码,我不太习惯VB.net):

// Code-behind
public override void OnApplyTemplate()
{
    base.OnApplyTemplate();
    var label = this.lblTime;
    label.Text = "00:00:00";
    label.Measure(); // Force it to measure
    label.Width = label.DesiredSize.Width;
}

This will force the width to stay constant. Depending on the font, you need to manually set the time value that takes up the most space.

这将迫使宽度保持不变。根据字体的不同,您需要手动设置占用最多空间的时间值。

Also, to be sure it works properly, you may need to wrap the Label in a Grid. Make the Grid have 3 columns, set the label in column 1 (middle column), and set the columndefinitions' widths to *, auto and * respectively in that order.

此外,为了确保它正常工作,您可能需要将Label包装在网格中。使网格有3列,在第1列(中间列)中设置标签,并将columndefinitions的宽度分别按顺序设置为*,auto和*。

#2


0  

Your Canvas has a width of 300. It looks to me as there is less than 300 px available. This is why the last column is smaller.

你的画布宽度为300.它对我来说,因为可用的不到300像素。这就是最后一栏较小的原因。

#3


0  

@Jai, thanks for pointing me in the direction of the .Measure() Sub. After fiddling around i ended up with the 3 column grid, measuring the size of the label with the new content, setting the size of the label. This causes the Column to realign, which holds the label in place.

@Jai,谢谢你指点我.Measure()Sub的方向。摆弄后我最终得到3列网格,用新内容测量标签的大小,设置标签的大小。这会导致Column重新对齐,从而将标签保持在原位。

The code: (created new WPF program for the test, The colors are to see the difference between child and parent)

代码:(为测试创建新的WPF程序,颜色是看孩子和父母之间的区别)

    <Grid Background="Tomato">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>

    <Label Name="lblTime"
                   Grid.Column="1"
                   Grid.Row="0"
                   Content = "-- : -- : --"
                   FontSize="50"
                   Foreground="Black"
                   Background="Beige"
                   HorizontalContentAlignment="Left"
                   VerticalAlignment="Center"
                   FontFamily="DS-Digital"/>
</Grid>

And the code behind it:

它背后的代码:

Class MainWindow

MainWindow类

''' <summary>
''' Timer for updating the time Clock
''' </summary>
Dim WithEvents tmrSystemTime As New DispatcherTimer With {.Interval = TimeSpan.FromSeconds(1)} 'Set Timer interval on every second.

Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    ' Add any initialization after the InitializeComponent() call.
    tmrSystemTime.Start()
End Sub

Private Sub SystemTime_Tick(sender As Object, e As EventArgs) Handles tmrSystemTime.Tick
    'Set the time in the label
    lblTime.Content = Now.ToString("HH : mm : ss")

    'Measure and set the size of the label
    MeasureSizeTimeLabel()
End Sub

''' <summary>
''' Measure the Max Size of the label with a specific Format
''' </summary>
Private Sub MeasureSizeTimeLabel()

    'Store the Max size of the Time Label in this variable
    Dim MaxClockSize As Size

    'Measure the Max size of the clock label and use this width
    'lblTime.Content = "00 : 00 : 00"
    lblTime.Measure(New Size(Double.PositiveInfinity, Double.PositiveInfinity))
    MaxClockSize = lblTime.DesiredSize

    'Now Set the size of the label
    lblTime.Width = MaxClockSize.Width
    lblTime.Height = MaxClockSize.Height
End Sub

Thanks all for the help, appreciate the effort and time! :-)

感谢大家的帮助,感谢您的努力和时间! :-)