WPF位置TextBlock/Label在行中心

本文关键字:Label 位置 TextBlock WPF | 更新日期: 2023-09-27 18:14:09

我试图在画布内用MVVM表示加权图所以我将图形的顶点和边表示为可观察集合,并将它们放入画布ItemsControl。但是我找不到任何合理的方法来定位表示线(图形边缘)中心的权重的文本

my canvas xaml:

<Canvas Background="Linen" ClipToBounds="True"
            Grid.Row="0" Grid.Column="0">
        <ItemsControl ItemsSource="{Binding EdgeItems}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Line Stroke="Black" StrokeThickness="4" 
                          X1="{Binding V1.X}" Y1="{Binding V1.Y}"
                          X2="{Binding V2.X}" Y2="{Binding V2.Y}"/>                                                        
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Canvas>

我想要得到什么

WPF位置TextBlock/Label在行中心

添加到您的EdgeItem类(或您的EdgeItems集合中的任何内容)。

    //  When V1 or V2 changes, raise PropertyChanged("Margin")
    public Thickness Margin => new Thickness(Left, Top, 0, 0);
    public double Left => Math.Min(V1.X, V2.X);
    public double Top => Math.Min(V1.Y, V2.Y);

我假设EdgeItem具有Weight属性-如果没有,Weight是您想要在行中心显示的任何属性的替身。我本以为Canvas.LeftCanvas.Top会起作用,但对我来说,它们在这种情况下不起作用。

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Grid>
            <Line 
                Stroke="Black" 
                StrokeThickness="4" 
                X1="{Binding V1.X}" 
                Y1="{Binding V1.Y}"
                X2="{Binding V2.X}" 
                Y2="{Binding V2.Y}"
                />
            <Label 
                Background="#ccffffff"
                Content="{Binding Weight}" 
                Margin="{Binding Margin}"
                HorizontalAlignment="Center" 
                VerticalAlignment="Center" 
                />
        </Grid>
    </DataTemplate>
</ItemsControl.ItemTemplate>
<标题> 第二个方法

或者,不要将MarginLeftTop属性添加到EdgeItem,而是使用值转换器生成边距Thickness。我对EdgeItem上的这些属性并不疯狂,但另一方面,{Binding}上的值转换器是提高PropertyChanged的问题,如果你碰巧在运行时改变V1V2。解决方案是使其成为多值转换器,并使用多绑定分别绑定V1V2。我只是懒得写XAML。

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Grid>
            <Line 
                Stroke="Black" 
                StrokeThickness="4" 
                X1="{Binding V1.X}" 
                Y1="{Binding V1.Y}"
                X2="{Binding V2.X}" 
                Y2="{Binding V2.Y}"
                />
            <Label 
                Background="#ccffffff"
                Content="{Binding Weight}" 
                Margin="{Binding Converter={local:EdgeItemMargin}}"
                HorizontalAlignment="Center" 
                VerticalAlignment="Center" 
                />
        </Grid>
    </DataTemplate>
</ItemsControl.ItemTemplate>

转换器:

public class EdgeItemMargin : MarkupExtension, IValueConverter
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }
    public object Convert(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        var edge = (EdgeItem)value;
        return new Thickness(
            Math.Min(edge.V1.X, edge.V2.X), 
            Math.Min(edge.V1.Y, edge.V2.Y), 
            0, 0);
    }
    public object ConvertBack(
        object value, 
        Type targetType, 
        object parameter, 
        CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}