I have a nested WPF View where I pass Objects through to the inner layers via Dependency Properties.
My outer XAML layer passes data into RetentionChartControl.ChartParams
:
<local:RetentionChartControl ChartParams="{Binding PeakRow.Chartparams[0], RelativeSource={RelativeSource AncestorType={x:Type local:PeakrowChartGroupControl}}}"></local:RetentionChartControl>
In my most inner layer I have the following XAML code:
<UserControl x:Class="DryLab.Peakmovement.RetentionChartControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:DryLab.Peakmovement"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
mc:Ignorable="d"
x:Name="uc"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<lvc:CartesianChart x:Name="cc" Series="{Binding ChartParams.Seriescollection, RelativeSource={RelativeSource AncestorType={x:Type local:RetentionChartControl}}}" >
<lvc:CartesianChart.DataTooltip>
<lvc:DefaultTooltip SelectionMode="OnlySender" />
</lvc:CartesianChart.DataTooltip>
<lvc:CartesianChart.AxisY>
<lvc:Axis Foreground="Black" Title="{Binding ChartParams.TitleAxY, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:RetentionChartControl}} }" LabelFormatter="{Binding ChartParams.Formatter, RelativeSource={RelativeSource AncestorType={x:Type local:RetentionChartControl}}}">
</lvc:Axis>
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.AxisX>
<lvc:Axis Foreground="Black" Title="{Binding ChartParams.TitleAxX, RelativeSource={RelativeSource AncestorType={x:Type local:RetentionChartControl}}}" Labels="{Binding ChartParams.Labels, RelativeSource={RelativeSource AncestorType={x:Type local:RetentionChartControl}} }"></lvc:Axis>
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
</UserControl>
Now the Binding for <lvc:Cartesian Chart>
(From LiveCharts https://lvcharts.net/App/examples/v1/wpf/Basic%20Line%20Chart) is working, the ChartParams Variable is fully evaluated and i can Access the Seriescollection.
However if i look at the deeper nested <lvc:Axis>
(via LiveVisualTree) the Title
Property is never evaluated.
What have i missed? Why cant i bind to ChartParams from within <lvc:Axis>
?
Any help is appreciated, will post further code if necessary.
Edit:
I should add, that when the application is running, and I touch my Axis.Title
in Xaml, it reevaluates and then shows the results as espected
The problem is, that the Axis
element is not added to the visual tree the moment the bindings are resolved. All visible elements that are a child of the chart's underlying Canvas
, are added later (long time after the chart control's FrameworkElement.Loaded
event was raised). Therefore data bindings that bind e.g. Axis
or Separator
etc. to their visual parent using RelativeSource
will point to nowhere (unless you set the binding after the relevant target elements are added to the Canvas
(requires C# instead of XAML) by observing the CartesianChart.Content.LayoutUpdated
event, but I recommend against this).
The recommended solution is to bind to the DataContext
instead.
You can either set the UserControl
itself as its own DataContext
:
PeakrowChartGroupControl.xaml.cs
partial class PeakrowChartGroupControl : UserControl
{
public PeakrowChartGroupControl()
{
InitializeComponent();
this.DataContext = this;
}
}
PeakrowChartGroupControl.xaml
<UserControl x:Class="DryLab.Peakmovement.RetentionChartControl">
<Grid>
<lvc:CartesianChart x:Name="cc" Series="{Binding ChartParams.Seriescollection}">
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="{Binding ChartParams.TitleAxY}"
LabelFormatter="{Binding ChartParams.Formatter}" />
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="{Binding ChartParams.TitleAxX}"
Labels="{Binding ChartParams.Labels}" />
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
</UserControl>
Or alternatively e.g., in case the UserControl.DataContext
is already set to something else, you can explicitly set the charts DataContext
to e.g., the ChartParams
property of RetentionChartControl
:
PeakrowChartGroupControl.xaml
<UserControl x:Class="DryLab.Peakmovement.RetentionChartControl">
<Grid>
<lvc:CartesianChart DataContext="{Binding ChartParams, RelativeSource={RelativeSource AncestorType=local:RetentionChartControl}}"
Series="{Binding Seriescollection}">
<lvc:CartesianChart.AxisY>
<lvc:Axis Title="{Binding TitleAxY}"
LabelFormatter="{Binding Formatter}" />
</lvc:CartesianChart.AxisY>
<lvc:CartesianChart.AxisX>
<lvc:Axis Title="{Binding TitleAxX}"
Labels="{Binding Labels}" />
</lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
</Grid>
</UserControl>