I have a Path who's data comes from a LineGeometry. I also have a TextBlock that is created when the path is created. What is the correct way to get the TextBlock's position to follow the Path's position?
2 回答
有很多方法
- 在自定义面板中包含 Path 和 TestBlock,并实现 MeasureOverride 和 ArrangeOverride
- 使用已经存在的面板(Grid、StackPanel 等)
- 监听 Path 对象的 LayoutUpdated,然后使用 TranslatePoint 方法定位 TextBlock
每种方式都有其缺点和优点,这取决于整个窗口的布局方式以及路径布局变化的动态程度
The perhaps simplest solution would be to put the Path and the TextBlock into a common container that perform the necessary layout on the TextBlock. This could be a Grid:
<Canvas>
<Grid>
<Path ... />
<TextBlock Text="Label" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Canvas>
You could also position the TextBlock relative to the Path's center by binding its RenderTransform
(or LayoutTransform
) to the Path's Geometry
and use a binding converter for the actual calculation. The converter would for example convert a Geometry into a TranslateTransform
. Note that it does not even require the Geometry to be a LineGeometry. It just uses the Geometry's Bounds
. You could however do any specialized calculation, depending on the actual type of Geometry.
public class GeometryCenterConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var result = new TranslateTransform();
var geometry = value as Geometry;
if (geometry != null)
{
result.X = (geometry.Bounds.Left + geometry.Bounds.Right) / 2;
result.Y = (geometry.Bounds.Top + geometry.Bounds.Bottom) / 2;
}
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
You would write the binding like this:
<Path Name="path" ... />
<TextBlock Text="Label"
RenderTransform="{Binding Path=Data, ElementName=path,
Converter={StaticResource GeometryCenterConverter}}"/>
Note that the above example does not take any alignment of the TextBlock into account. If you need it to be centered or perhaps right- and bottom-aligned, you may need a more complex binding (perhaps a MultiBinding) or you may put all elements in a Canvas and set Canvas.Left
and Canvas.Top
appropriately on the TextBlock.