为什么Path的数据绑定's填充工作,但对其任何子元素的任何绑定都不会;t



我有一个ItemsControl,它绑定到一个可观察的集合。在控件ItemTemplate中,我有一个Canvas,它包含一个我用来绘制一些线段的路径。像这样:

       <ItemsControl
        ItemsSource="{Binding CombinedPieChartData}">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Canvas>
                        <Path Stroke="Black" StrokeThickness="1" Fill="{Binding Color}">
                            <Path.Data>
                                <GeometryGroup>
                                    <PathGeometry>
                                        <PathFigure StartPoint="{Binding FirstPoint1}">
                                            <PathFigure.Segments>
                                                <LineSegment Point="{Binding SecondPoint1}"/>
                                            </PathFigure.Segments>
                                        </PathFigure>
                                    </PathGeometry>
                                </GeometryGroup>
                            </Path.Data>
                        </Path>
                    </Canvas>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

将Path的Fill属性绑定到Color属性效果良好。但是,绑定到PathFigure的起点和线段点不起作用。它显示正确,但报告这些错误:

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=FirstPoint1; DataItem='PieChartDataPoint' (HashCode=35164785); target element is 'PathFigure' (HashCode=9043297); target property is 'StartPoint' (type 'Point')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=SecondPoint1; DataItem='PieChartDataPoint' (HashCode=35164785); target element is 'LineSegment' (HashCode=52141992); target property is 'Point' (type 'Point')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=FirstPoint1; DataItem='PieChartDataPoint' (HashCode=52449849); target element is 'PathFigure' (HashCode=8195173); target property is 'StartPoint' (type 'Point')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=SecondPoint1; DataItem='PieChartDataPoint' (HashCode=52449849); target element is 'LineSegment' (HashCode=41799477); target property is 'Point' (type 'Point')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=FirstPoint1; DataItem='PieChartDataPoint' (HashCode=15121425); target element is 'PathFigure' (HashCode=46419306); target property is 'StartPoint' (type 'Point')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=SecondPoint1; DataItem='PieChartDataPoint' (HashCode=15121425); target element is 'LineSegment' (HashCode=50982559); target property is 'Point' (type 'Point')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=FirstPoint1; DataItem=null; target element is 'PathFigure' (HashCode=61646970); target property is 'StartPoint' (type 'Point')
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=SecondPoint1; DataItem=null; target element is 'LineSegment' (HashCode=38860075); target property is 'Point' (type 'Point')

我真的很困惑为什么会出现这些错误,无法在网上找到任何帮助。有什么建议吗?


这是我在Observable集合中使用的类

public class PieChartDataPoint : ObservableObject
    {
        public string Catagory { get; set; }
        public double Value { get; set; }
        public SolidColorBrush Color { get; set; }
        private Point firstPoint1;
        public Point FirstPoint1
        {
            get
            {
                return firstPoint1;
            }
            set
            {
                firstPoint1 = value;
                RaisePropertyChangedEvent("FirstPoint1");
            }
        }
        private Point secondPoint1;
        public Point SecondPoint1
        {
            get
            {
                return secondPoint1;
            }
            set
            {
                secondPoint1 = value;
                RaisePropertyChangedEvent("SecondPoint1");
            }
        }
        private Size pieSize;
        public Size PieSize
        {
            get
            {
                return pieSize;
            }
            set
            {
                pieSize = value;
                RaisePropertyChangedEvent("PieSize");
            }
        }
        private int colorIndex = 0;
        public int ColorIndex
        {
            get { return colorIndex; }
            set
            {
                colorIndex = value;
                Color newColor = Utilities.SelectColour(value);
                newColor.A = 190;
                this.Color = new SolidColorBrush(newColor);
            }
        }
        public double Fraction { get; set; }
        public string Percentage
        {
            get
            {
                return String.Format("{0:P2}", Fraction);
            }
        }
        public PieChartDataPoint(string Catagory, double Value, int ColorIndex, double Fraction)
        {
            this.Catagory = Catagory;
            this.Value = Value;
            this.ColorIndex = ColorIndex;
            this.Fraction = Fraction;
        }
    }

因此,在xaml中设置Path的Data属性。此属性的类型为Geometry,它不是视觉树的一部分(几何体本身不是视觉控件,它用于渲染路径)。这意味着:它不继承"父"DataContext,因为它实际上不在可视化树中,也没有父(这比这更复杂,因为一些非可视化的元素确实继承了DataContext,但在这种情况下不是)。

您可以在DataTemplate中创建"fake"元素,该元素将继承父DataContext,然后将其用作绑定的源。任何"假"元素都不会起作用,请参阅本文:http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/

现在,从该文章中复制BindingProxy类,然后:

<ItemsControl
    ItemsSource="{Binding CombinedPieChartData}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Canvas>
                <Canvas.Resources>
                    <local:BindingProxy  x:Key="proxy" Data="{Binding}" />
                </Canvas.Resources>
                <Path Stroke="Black" StrokeThickness="1" Fill="{Binding Color}">
                    <Path.Data>
                        <GeometryGroup>
                            <PathGeometry>
                                <PathFigure StartPoint="{Binding Source={StaticResource proxy}, Path=Data.FirstPoint1}">
                                    <PathFigure.Segments>
                                        <LineSegment Point="{Binding Source={StaticResource proxy}, Path=Data.SecondPoint1}"/>
                                    </PathFigure.Segments>
                                </PathFigure>
                            </PathGeometry>
                        </GeometryGroup>
                    </Path.Data>
                </Path>
            </Canvas>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

您所做的是在可视化元素的资源中创建"代理"控件,该控件以特殊方式构建(继承自Freezable-请参阅上面的文章),并且,尽管不是可视化树的一部分,但将继承父DataContext。然后,您只需使用该代理作为绑定的源。