为什么 Path 填充的数据绑定有效,但其任何子元素的任何绑定都不起作用?

Tim*_*oth 3 c# data-binding wpf xaml

我有一个绑定到可观察集合的 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>
Run Code Online (Sandbox Code Playgroud)

将 Path 的 Fill 属性绑定到 Color 属性工作正常。但是绑定到 PathFigure 的 StartPoint 和 LineSegments Point 不起作用。它显示正确,但它报告这些错误:

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')
Run Code Online (Sandbox Code Playgroud)

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


这是我在 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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

Evk*_*Evk 5

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

您可以做的是在您的 DataTemplate 中创建“假”元素,该元素将继承父 DataContext,然后将其用作绑定的源。没有任何“假”元素会做,请参阅这篇文章:http : //www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not -遗传/

现在,从那篇文章中复制 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>
Run Code Online (Sandbox Code Playgroud)

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