Dependency properties fail to get the context of the parent

A forum dedicated to WPF version of LightningChart Ultimate.

Moderator: Queue Moderators

Post Reply
TRVRSE
Posts: 21
Joined: Fri May 30, 2014 1:27 pm

Dependency properties fail to get the context of the parent

Post by TRVRSE » Fri May 30, 2014 1:57 pm

Preface: I'm new to WPF in general. This could be a poor expectation of WPF on my part.

Goal: I'm trying to bind the Margins property of a ViewXY graph to a property in the data context of the containing lightning chart.

Setup: I have a Data Context class that has a property SampleMargin.
I have defined in the xaml a lightning chart object which contains a ViewXY object.

My confusion comes when trying to bind the ViewXY.Margins property to the SampleMargin property of the data context.

I can successfully bind the SampleMargin property to the LightningChart.Margin property. But I cannot bind the property to the LightningChart.ViewXY.Margins property.
See the code below for binding.
Succeeds: Margin="{Binding SampleMargin}" >
Fails: <lcu:ViewXY Margins="{Binding SampleMargin}">

The debug output shows:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=SampleMargin; DataItem=null; target element is 'ViewXY' (HashCode=216817); target property is 'Margins' (type 'Thickness')
Are my expectations incorrect? Should I be able to bind the ViewXY.Margins property to a property in the data context? If so, how can I achieve this?


Data Context class:

Code: Select all

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;

namespace BindingSample
{
	public class SampleContext : DependencyObject
	{
		public Thickness SampleMargin
		{
			get
			{
				return (Thickness)GetValue(SampleMarginProperty);
			}

			set
			{
				SetValue(SampleMarginProperty, (Object)value);
			}
		}

		public static readonly DependencyProperty SampleMarginProperty;

		static SampleContext()
		{
			SampleMarginProperty =
				DependencyProperty.Register(
					"SampleMargin",
					typeof(Thickness),
					typeof(SampleContext),
					new PropertyMetadata(
						(Object)(new Thickness( 10 )),
						null
					)
				);
		}
	}
}

Window Xaml:

Code: Select all

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:lcu="http://www.arction.com/schemas/" x:Class="BindingSample.MainWindow"
				xmlns:local="clr-namespace:BindingSample"
        Title="MainWindow" Height="350" Width="525">
	<Window.DataContext>
		<local:SampleContext />
	</Window.DataContext>

	<Grid>
		<lcu:LightningChartUltimate 
			Content="LightningChartUltimate"
			HorizontalAlignment="Stretch"
			VerticalAlignment="Stretch"
			Margin="{Binding SampleMargin}" >

			<lcu:LightningChartUltimate.ViewXY>
				<lcu:ViewXY Margins="{Binding SampleMargin}">
					<lcu:ViewXY.AxisLayout>
						<lcu:AxisLayout AutoAdjustMargins="False"/>
					</lcu:ViewXY.AxisLayout>

					<lcu:ViewXY.YAxes>
						<lcu:AxisY/>
					</lcu:ViewXY.YAxes>
					<lcu:ViewXY.XAxes>
						<lcu:AxisX/>
					</lcu:ViewXY.XAxes>
				</lcu:ViewXY>
			</lcu:LightningChartUltimate.ViewXY>
		</lcu:LightningChartUltimate>
	</Grid>
</Window>

ArctionJari

Re: Dependency properties fail to get the context of the par

Post by ArctionJari » Mon Jun 02, 2014 9:25 am

I copy-pasted your code and I also get the same "error" in my output window as you even though the program starts without problems. We'll look into this and let you know when we know more.

One thing I noticed in your code is that you have set LightningChartUltimate.Content to "LightningChartUltimate". If you set Content property, chart will lose its rendering object and it will just render "LightningChartUltimate" string. Event though chart is rendered correctly when you start your application it is not recommended to set Content property.

If you want to give the chart a name, use LightningChartUltimate.ChartName. You can also use LightningChartUltimate.Title.Text property to set chart's title.

ArctionJari

Re: Dependency properties fail to get the context of the par

Post by ArctionJari » Mon Jun 02, 2014 9:59 am

By the way, do you want to bind the data context object's property to both chart's Margin and ViewXY object's Margins properties? I didn't notice that you are binding to both of them so I missed ViewXY.Margins binding. :)

ViewXY class is not currently derived from FrameworkElement class. We are working on this matter to see what is the best way to handle this situation. You can test this yourself by removing the binding from ViewXY's property. You shouldn't see the error message anymore after this.

I suggest that you move your SampleContext object from DataContext to Window.Resources:

Code: Select all

<Window.Resources>
    <local:SampleContext x:Key="sc"/>
</Window.Resources>
Then create binding like this:

Code: Select all

<lcu:ViewXY Margins="{Binding Source={StaticResource ResourceKey=sc}, Path=SampleMargin}">
Same for Margin property of LightningChartUltimate object if you want to bind both of them.

TRVRSE
Posts: 21
Joined: Fri May 30, 2014 1:27 pm

Re: Dependency properties fail to get the context of the par

Post by TRVRSE » Tue Jun 03, 2014 3:37 pm

By the way, do you want to bind the data context object's property to both chart's Margin and ViewXY object's Margins properties?
My goal is to bind the data context object's property to the ViewXY object's Margins property. The reason that I set the Lightning chart object's Margin property was to provide an example that binding worked.


I see your solution for changing the SampleMargin class from the data context to a static Windows Resource. This would fix the issue I have described. But, in my effort to simplify my question, I have simplified my problem too much. I failed to describe all constraints and components of my application.

In my application I'm implement MVVM with the help of a framework. In this framework, during runtime, the data context of the view is set to the viewmodel. This is analogous to the setting of the data context of my MainWindow to be the SampleContext object. The view model is analogous to SampleMargin, in that it has a Margin property showing. Any changes to this property should bubble up to the view and be reflected in the chart.

The suggestion to move the SampleMargin class from data context to a static Windows Resource is not realistic for my application, as the data context is set at run time within my framework. If you have any alternative solutions that would help me achieve my goal, it would be much appreciated. Again, my Goal was to simply bind a ViewXY Property to a property in the viewmodel. It seems I may have to force the ViewXY property to update by using the codebehind.

It appears that you intend to have ViewXY, and hopefully other classes, derive from FrameworkElement. I fear that until this happens, binding its properties to a data context object's properties is not feasible. Does this seem like an accurate assumption?

ArctionJari

Re: Dependency properties fail to get the context of the par

Post by ArctionJari » Wed Jun 04, 2014 9:24 am

Yes, the problem currently is that ViewXY is derived from DependencyObject hence not allowing parent DataContext "inheritance" since it's not in the logical tree. FrameworkElement is a little bit overkill because chart's properties are not actually visual objects - i.e. they are not rendered by WPF. FrameworkElement has many rendering related properties (e.g. ActualWidth, ActualHeight, ...) which would just confuse everyone since the values would not reflect the actual situation.

We have, however, a couple of good ideas to enable DataContext inheritance to chart's child properties and if they work well we will implement the revised class inheritance in the near future. Currently parent DataContext is not usable in chart's child properties (e.g. binding to ViewXY.Margins property).

Maybe using FindAncestor in binding might work. Haven't tried that yet.

TRVRSE
Posts: 21
Joined: Fri May 30, 2014 1:27 pm

Re: Dependency properties fail to get the context of the par

Post by TRVRSE » Thu Jun 05, 2014 5:30 pm

I tried binding by using FindAncestor.

Code: Select all

<lcu:ViewXY  Margins="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type lcu:LightningChartUltimate}}, Path=DataContext.SampleMargin}" >
I received the following error:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='Arction.WPF.LightningChartUltimate.LightningChartUltimate', AncestorLevel='1''. BindingExpression:Path=DataContext.SampleMargin; DataItem=null; target element is 'ViewXY' (HashCode=5430406); target property is 'Margins' (type 'Thickness')
So searching for the ancestor failed and I'm not sure why.

TRVRSE
Posts: 21
Joined: Fri May 30, 2014 1:27 pm

Re: Dependency properties fail to get the context of the par

Post by TRVRSE » Thu Jun 05, 2014 5:34 pm

But I do have a solution, or at least a temporary one. Unfortunately, the binding takes place in the code behind, which was something I wished to avoid.


MainWindow.xaml.cs:

Code: Select all

using Arction.WPF.LightningChartUltimate.Views.ViewXY;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BindingSample
{
	/// <summary>
	/// Interaction logic for MainWindow.xaml
	/// </summary>
	public partial class MainWindow : Window
	{
		public MainWindow()
		{
			InitializeComponent();

			// Bind the data contexts SampleMargin property to the Margins property of the ViewXY.
			Binding MarginsBinding = new Binding("SampleMargin");
			MarginsBinding.Source = DataContext;
			BindingOperations.SetBinding(chart.ViewXY, ViewXY.MarginsProperty, MarginsBinding);
		}
	}
}
And the updated xaml
MainWindow.Xaml:

Code: Select all

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:lcu="http://www.arction.com/schemas/" x:Class="BindingSample.MainWindow"
				xmlns:local="clr-namespace:BindingSample"
        Title="MainWindow" Height="350" Width="525">
	<Window.Resources>
		<Thickness x:Key="thick" Left="12" Top="8" Right="3"  Bottom="5" />
	</Window.Resources>
	<Window.DataContext>
		<local:SampleContext/>
	</Window.DataContext>

	<Grid>
		<lcu:LightningChartUltimate x:Name="chart"
			HorizontalAlignment="Stretch"
			VerticalAlignment="Stretch" >

			<lcu:LightningChartUltimate.ViewXY>
				<lcu:ViewXY>
					<lcu:ViewXY.GraphBackground>
						<lcu:Fill Color="Gray"/>
					</lcu:ViewXY.GraphBackground>
					<lcu:ViewXY.AxisLayout>
						<lcu:AxisLayout AutoAdjustMargins="False"/>
					</lcu:ViewXY.AxisLayout>

					<lcu:ViewXY.YAxes>
						<lcu:AxisY/>
					</lcu:ViewXY.YAxes>
					<lcu:ViewXY.XAxes>
						<lcu:AxisX/>
					</lcu:ViewXY.XAxes>
				</lcu:ViewXY>
			</lcu:LightningChartUltimate.ViewXY>
		</lcu:LightningChartUltimate>
	</Grid>
</Window>
This appropriately binds the SampleMargins property of the datacontext to the ViewXY objects Margins property.

TRVRSE
Posts: 21
Joined: Fri May 30, 2014 1:27 pm

Re: Dependency properties fail to get the context of the par

Post by TRVRSE » Thu Jun 05, 2014 5:37 pm

I am looking forward to future releases in hopes of simplifying the binding of ViewModel properties to LightningChart properties.

Post Reply