您可以通过将标签的边距绑定到标签的ActualWidth 和ActualHeight 并将这些值乘以-0.5 来实现这一点。这会将标签向左移动其宽度的一半;并将标签向上移动一半高度。
这是一个例子:
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>
红色矩形突出显示标签“MMMMMM”居中的坐标 (40, 40)。
转换器:
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();
}
}
结果如下:
为了以编程方式执行此操作,请定义一个附加属性 Mover.MoveToMiddle,如下所示:
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 设置为true 意味着该框架元素的边距自动绑定到其实际宽度和高度,以便将框架元素移动到其中心点。
您可以像这样在 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 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 而不是Margin。在这种情况下,转换器会返回
return new TranslateTransform(-width / 2, -height / 2);
附加属性的回调方法将包含以下几行:
if ((bool)e.NewValue)
{
...
element.SetBinding(UIElement.RenderTransformProperty, multiBinding);
}
else
{
element.ClearValue(UIElement.RenderTransformProperty);
}
此替代方法的优点是附加属性的效果在 Visual Studio 设计器中可见(设置 Margin 属性时不是这种情况)。