ItemPresenter使用Canvas ItemPanel在ItemTemplate中使用PathGeometry绝对位置混乱

时间:2016-10-17 14:08:18

标签: wpf canvas itemscontrol pathgeometry

我有一个ItemsControlCanvasItemsPanelPathItemTemplate。目标是绘制图形,因此Path.Data应包含要使用绝对坐标在“画布”中绘制的几何体。

如果我实例化Canvas并将路径直接放在其中,它就可以正常工作。

但是如果我使用ItemsControl,则每个Path最终都会包含在ContentPresenter中,然后坐标会丢失,因为ContentPresenter会与Canvas原点对齐。

这是我的代码:

        <ItemsControl
            ItemsSource="{Binding Signals}"
        >
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Path 
                        Stroke="Red"
                        StrokeThickness="1" 
                        StrokeDashCap="Round" 
                        StrokeLineJoin="Round" 
                        Stretch="Fill" 
                        Data={Binding Converter=SignalToGeometryConverter}
                    />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

1 个答案:

答案 0 :(得分:3)

如果你确实需要Canvas ItemsPanel ItemsControl,{em>和,你真的需要填写父母,你可能是在一个艰难的地方。如果您Grid ItemsPanel可以获得ContentPresenter,那么您已经完成了设置。

你在这里得到的不是Stretch,而是Path。这导致"M 100,100 L 200,200"填补其父级 - 但不是你想象的方式。除了Stretch以外的任何NoneStretch="Fill"将从父级的左上角开始绘制一条线。它将使用的边界框是路径几何实际使用的最大和最小x和y值。它假设你只关心你打扰去的地方。如果您正在叠加多个具有不同左上角(和右下)边界的路径,则它们将被缩放并以不同方式进行偏移,从而对所有内容进行总哈希处理。

当你想到它时,即使伸展确实从0,0开始,它怎么会知道用于右下界?这些路径彼此不了解。如果你有一个Path,并将你当前的每个东西作为一个不同的数字添加到它,那将是一回事。但是这样,他们没有意识到共同的参考框架。

所以最快的解决方法是删除Canvas,但是什么都不会延伸。只要您使用ItemsPanel作为M 0,0 M xmax,ymax ,您也可以不尝试延伸路径,因为(据我所知,通过测试)它们无论如何都不会伸展那种情况。

如果你想要伸展,首先你需要所有的路径都有相同的边界框,无论它们是否实际使用整个东西。这意味着首先计算您将需要多少水平和垂直空间,并使用

为每个路径数据添加前缀
Path

...在移动到实际点之前,您要启动Canvas at。

然后将Grid更改为<Grid> <ItemsControl ItemsSource="{Binding Signals, RelativeSource={RelativeSource AncestorType=Window}}" > <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Grid /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate> <DataTemplate> <Path Stroke="DeepSkyBlue" StrokeThickness="1" Data="{Binding}" Stretch="Fill" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid>

以下是我测试过的代码:

XAML

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        int left = 10;
        int top = 100;
        int bottom = 200;

        var signals = 
            Enumerable.Range(0, 19)
            .Select(n => $"M 0,0 M 300,300 M {(n * 10) + left},{top} L {(n * 15) + left},{bottom}")
            .ToList();

        //  Show shared bounding box
        signals.Add("M 0,0 L 300,0 L 300,300 L 0,300 Z");

        Signals = signals;
    }

    public IList Signals
    {
        get { return (IList)GetValue(SignalsProperty); }
        set { SetValue(SignalsProperty, value); }
    }

    public static readonly DependencyProperty SignalsProperty =
        DependencyProperty.Register("Signals", typeof(IList), typeof(MainWindow),
            new PropertyMetadata(null));
}

C#

services=["service1","service2","service3"]
ports=[11001,11002,11003]