Reputation: 510
I have an ItemsControl that is bound to an observable collection. Within the controls ItemTemplate I have a Canvas which contains a path that I draw some line segments with. Like so:
<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>
Binding the Path's Fill property to the Color property works fine. However the binding to the PathFigure's StartPoint and the LineSegments Point does not work. It displays correctly however it reports these errors:
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')
I am really confused as to why these errors are there and cannot find any help online. Any suggestions?
Here is the class that I use in my Observable collection
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;
}
}
Upvotes: 3
Views: 750
Reputation: 101443
So in your xaml you set Data property of Path. This property is of type Geometry and it's not part of visual tree (geometry itself is not a visual control - it is used to render path). What that means is: it does not inherit "parent" DataContext, because it's actually not in a visual tree and has no parent (it's a bit more complicated than this, because some elements which are not visual do inherit DataContext, but not in this case).
What you can do is create "fake" element in your DataTemplate which will inherit parent DataContext, and then use it as a source for your Bindings. Not any "fake" element will do, see this article: http://www.thomaslevesque.com/2011/03/21/wpf-how-to-bind-to-data-when-the-datacontext-is-not-inherited/
Now, copy BindingProxy class from that article and then:
<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>
What you did is created "proxy" control in resources of your visual element, which is constructed in a special way (is inherited from Freezable - see article above), and, despite not a part of visual tree, will inherit parent DataContext. Then you just use that proxy as a source of your bindings.
Upvotes: 5