WPF在行中心位置TextBlock / Label

时间:2016-10-21 16:53:11

标签: c# wpf xaml canvas binding

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

我的画布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>

What i want to get

1 个答案:

答案 0 :(得分:1)

添加到您的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时遇到问题,如果您碰巧改变V1运行时{1}}或V2。解决方案是使其成为多值转换器,并使用多重绑定分别绑定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();
    }
}