Can anyone tell me how to center a polygon object within a given row/column of a Grid control?
The example that I have tried is taken from msdn.
<Grid x:Name="LayoutRoot" >
<Polygon Points="300,200 400,125 400,275 300,200"
Stroke="Purple"
StrokeThickness="2"
HorizontalAlignment="Center"
VerticalAlignment="Center" >
<Polygon开发者_如何学Go.Fill>
<SolidColorBrush Color="Blue" Opacity="0.4" />
</Polygon.Fill>
</Polygon>
Cheers,
Xam
Add the attributes :-
HorizontalAlignment="Center" VerticalAlignment="Center"
to the Polygon
.
Although a height and width are implied by the bounds of the polygon, it defaults to the size of the container.
If you just set
HorizontalAlignment="Center" VerticalAlignment="Center"
it will position the polygon's top-left in the centre.
You also have to explicitly set the height and width of the polygon to centre it and retain its bounds
Sample polygon Xaml with dimensions added:
<Grid x:Name="LayoutRoot">
<Path Data="M0.5,41.5 L201,0.5 L302,115 L157.25,157 z" Fill="#FFF4F4F5" Stroke="Black" UseLayoutRounding="False" HorizontalAlignment="Center" VerticalAlignment="Center" Width="302.5" Height="157.5"/>
</Grid>
Maybe this answer applies here too.
It uses a CenterConverter
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();
}
}
And binds it in XAML like this
<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>
To be able to use this in C# too and not only in XAML you need this class
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);
}
}
}
Use it in XAML like so
<Canvas>
<TextBlock Canvas.Left="40" Canvas.Top="40" TextAlignment="Center" Text="MMMMMM"
local:Mover.MoveToMiddle="True"/>
</Canvas>
Or in C# like so
Mover.SetMoveToMiddle(UIElement, true);
Alternatively you can manipulate the 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);
}
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).
In XAML this would look like this:
<Canvas>
<TextBlock x:Name="txt" Canvas.Left="40" Canvas.Top="40" TextAlignment="Center" Text="MMMMMM">
<TextBlock.RenderTransform>
<MultiBinding Converter="{StaticResource centerConverter}">
<Binding ElementName="txt" Path="ActualWidth"/>
<Binding ElementName="txt" Path="ActualHeight"/>
</MultiBinding>
</TextBlock.RenderTransform>
</TextBlock>
<Rectangle Canvas.Left="39" Canvas.Top="39" Width="2" Height="2" Fill="Red"/>
</Canvas>
TextBlock
was the control in question of the original answer. This way should be applicable to all objects of the class UIElement
though.
Note: all credit goes to the original poster of the above linked answer
精彩评论