在上一个WPF画布给定点中心文 [英] Center text at a given point on a WPF Canvas

查看:107
本文介绍了在上一个WPF画布给定点中心文的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 Controls.Canvas 上面有几种形状和想补充的是集中于特定点的文本标签(我画一棵树与标记的顶点)。什么是做到这一点编程方式在WPF中最简单的方法是什么?

I have a Controls.Canvas with several shapes on it and would like to add textual labels that are centered on given points (I'm drawing a tree with labelled vertices). What is the simplest way to do this programmatically in WPF?

我已经尝试设置的RenderTransform 并调用 Controls.Canvas.SetLeft 等,但无论位置标签,我想要它。 WPF似乎只在支持定位给定的左,右,上,下​​的坐标,而不是集中在一个给定的坐标和宽度属性 NaN的 ActualWidth的属性 0.0 时,我构建了画布

I have tried setting RenderTransform and calling Controls.Canvas.SetLeft etc. but neither position the label where I want it. WPF seems to support positioning only at given left, right, top and bottom coordinates and not centered on a given coordinate and the Width property is NaN and the ActualWidth property is 0.0 when I construct the Canvas.

推荐答案

您可以通过标签的边缘结合到 ActualWidth的的ActualHeight 的标签,并与-0.5乘以这些值。这会将通过其宽度的一半留下的标签;和它的一半的高度移动标签向上

You could achieve this by binding the margin of the label to the ActualWidth and ActualHeight of the label, and multiplying these values with -0.5. This moves the label left by half its width; and it moves the label upwards by half its height.

下面是一个例子:

XAML:

<Window x:Class="CenteredLabelTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CenteredLabelTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:CenterConverter x:Key="centerConverter"/>
    </Window.Resources>
    <Canvas>
        <TextBlock x:Name="txt" Canvas.Left="40" Canvas.Top="40" TextAlignment="Center" Text="MMMMMM">
            <TextBlock.Margin>
                <MultiBinding Converter="{StaticResource centerConverter}">
                        <Binding ElementName="txt" Path="ActualWidth"/>
                        <Binding ElementName="txt" Path="ActualHeight"/>
                </MultiBinding>
            </TextBlock.Margin>
        </TextBlock>
        <Rectangle Canvas.Left="39" Canvas.Top="39" Width="2" Height="2" Fill="Red"/>
    </Canvas>
</Window>

红色矩形突出的坐标(40,40),其上标注MMMMMM为中心。

The red rectangle highlights the coordinate (40, 40) on which the label "MMMMMM" is centered.

转换:

public class CenterConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue)
        {
            return DependencyProperty.UnsetValue;
        }

        double width = (double) values[0];
        double height = (double)values[1];

        return new Thickness(-width/2, -height/2, 0, 0);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

结果是这样的:

The result looks like this:

为了做到这一点编程,定义一个附加属性 Mover.MoveToMiddle ,像这样的:

In order to do that programmatically, define an attached property Mover.MoveToMiddle, like this:

public class Mover : DependencyObject
{
    public static readonly DependencyProperty MoveToMiddleProperty =
        DependencyProperty.RegisterAttached("MoveToMiddle", typeof (bool), typeof (Mover),
        new PropertyMetadata(false, PropertyChangedCallback));

    public static void SetMoveToMiddle(UIElement element, bool value)
    {
        element.SetValue(MoveToMiddleProperty, value);
    }

    public static bool GetMoveToMiddle(UIElement element)
    {
        return (bool) element.GetValue(MoveToMiddleProperty);
    }

    private static void PropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement element = sender as FrameworkElement;
        if (element == null)
        {
            return;
        }

        if ((bool)e.NewValue)
        {
            MultiBinding multiBinding = new MultiBinding();
            multiBinding.Converter = new CenterConverter();
            multiBinding.Bindings.Add(new Binding("ActualWidth") {Source = element});
            multiBinding.Bindings.Add(new Binding("ActualHeight") {Source = element});
            element.SetBinding(FrameworkElement.MarginProperty, multiBinding);
        }
        else
        {
            element.ClearValue(FrameworkElement.MarginProperty);
        }
    }

}

Mover.MoveToMiddle 设置为意味着该框架元素的边距自动绑定到其实际宽度和高度,使得所述框架元件移动到其中心点。

Setting Mover.MoveToMiddle to true means that the margin of that framework element is automatically bound to its actual width and height such that the framework element is moved to its center point.

您将使用它在你的XAML code是这样的:

You would use it in your XAML code like this:

<Window x:Class="CenteredLabelTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CenteredLabelTest"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:CenterConverter x:Key="centerConverter"/>
    </Window.Resources>
    <Canvas>
        <TextBlock Canvas.Left="40" Canvas.Top="40" TextAlignment="Center" Text="MMMMMM"
              local:Mover.MoveToMiddle="True"/>
        <Rectangle Canvas.Left="39" Canvas.Top="39" Width="2" Height="2" Fill="Red"/>
    </Canvas>
</Window>

另一种方法是绑定的,而不是保证金的RenderTransform 。在这种情况下,转换器将返回

An alternative would be to bind to RenderTransform instead of Margin. In this case, the converter would return

return new TranslateTransform(-width / 2, -height / 2);

和附加属性的回调方法将包含这些行:

and the attached property's callback method would contain these lines:

if ((bool)e.NewValue)
{
    ...
    element.SetBinding(UIElement.RenderTransformProperty, multiBinding);
}
else
{
    element.ClearValue(UIElement.RenderTransformProperty);
}

该替代的优点是附加属性的效果是明显的,在Visual Studio设计(这是不是设置保证金属性时的情况)。

This alternative has the advantage that the effect of the attached property is visible in the Visual Studio designer (which is not the case when setting the Margin property).

这篇关于在上一个WPF画布给定点中心文的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆