Reputation: 4895
i'm trying to centre my TextBlock within my Canvas, but it doesn't seem to be working as intended. I want the centre point to change obviously when more text is added so it stays centred.
This is what is being produced, 3 images showing when there is 1 number, 2 numbers and 3.
Here is my ControlTemplate
<Style TargetType="ProgressBar" x:Key="CircularProgress">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Grid x:Name="PathGrid" Margin="2" Width="200">
<Canvas>
<TextBlock x:Name="PathPercentage" Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Value, StringFormat={}{0}%}"
Foreground="White"
FontFamily="DefaultFont"
FontSize="{Binding ElementName=PathGrid, Path=ActualWidth, Converter={StaticResource SizeTextOnParent}}">
<TextBlock.Margin>
<MultiBinding Converter="{StaticResource CenterElement}">
<Binding ElementName="PathGrid" Path="ActualWidth"/>
<Binding ElementName="PathPercentage" Path="FontSize" />
<Binding ElementName="PathPercentage" Path="FontFamily"/>
<Binding ElementName="PathPercentage" Path="Text"/>
</MultiBinding>
</TextBlock.Margin>
</TextBlock>
<TextBlock Text="{Binding ElementName=PathPercentage, Path=Margin}" />
<Ellipse Fill="Transparent"
Stroke="#434953"
StrokeThickness="3"
Width="{Binding ElementName=PathGrid, Path=ActualWidth}"
Height="{Binding ElementName=PathGrid, Path=ActualWidth}" />
<Path x:Name="pathRoot"
Stroke="#8ab71c"
StrokeThickness="6"
HorizontalAlignment="Center"
VerticalAlignment="Top">
<Path.Data>
<PathGeometry>
<PathFigureCollection>
<PathFigure StartPoint="{Binding ElementName=PathGrid, Path=ActualWidth, Converter={StaticResource StartPointConverter}, Mode=OneWay}">
<ArcSegment Size="{Binding ElementName=PathGrid, Path=ActualWidth, Converter={StaticResource ArcSizeConverter}, Mode=OneWay}" SweepDirection="Clockwise">
<ArcSegment.IsLargeArc>
<MultiBinding Converter="{StaticResource LargeArcConverter}">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value" />
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum" />
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum" />
<Binding ElementName="FullyIndeterminateGridScaleTransform" Path="ScaleX" />
</MultiBinding>
</ArcSegment.IsLargeArc>
<ArcSegment.Point>
<MultiBinding Converter="{StaticResource ArcEndPointConverter}">
<Binding ElementName="PathGrid" Path="ActualWidth" />
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value" />
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum" />
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum" />
<Binding ElementName="FullyIndeterminateGridScaleTransform" Path="ScaleX" />
</MultiBinding>
</ArcSegment.Point>
</ArcSegment>
</PathFigure>
</PathFigureCollection>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And here is the CenterElement converter which defines the TextBlocks margin
namespace Test_Project.Converters
{
public class CenterElement : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double parentWidth = (double)values[0];
double fontSize = (double)values[1];
FontFamily fontFamily = (FontFamily)values[2];
string text = (string)values[3];
var textBlock = new TextBlock {
Text = text,
TextWrapping = TextWrapping.Wrap,
FontFamily = fontFamily,
FontSize = fontSize};
textBlock.Measure(new Size());
textBlock.Arrange(new Rect());
Console.WriteLine("Height: " + textBlock.ActualHeight + " Width: " + textBlock.ActualWidth + " Text: " + text);
double h = Math.Round(((parentWidth / 2) - (textBlock.ActualHeight / 2)),2);
double w = Math.Round(((parentWidth / 2) - (textBlock.ActualWidth / 2)), 2);
Thickness margin = new Thickness(w,h,0,0);
return margin;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Upvotes: 2
Views: 3279
Reputation: 16148
I'd just bind the width of the textbox to the ActualWidth
of the entire canvas and set TextAlignment to "Center":
<TextBlock Width="{Binding Path=ActualWidth, RelativeSource={RelativeSource AncestorType=Canvas}}" TextAlignment="Center" ...etc... />
And if you don't want it in the exact centre of the canvas then you can always offset it with Margin
.
Upvotes: 5