Binding to multiple LineGraphs from a ViewModel

Nov 9, 2009 at 12:56 AM

I understand that you can bind a line graph to a data source in the ViewModel (as shown below), but there doesn't seem to be a way to bind a list of IPointDataSource source objects (each with a different description and stroke pen)  from the ViewModel.  I am guessing that the ChartPlotter would need to act like a ItemPresenter with support for ItemTemplate in order to pull this off.  Is there something that I am missing that can be used to do this?

<d3:ChartPlotter Name="plotter">
	<d3:LineGraph DataSource="{Binding Data}">
		<d3:LineGraph.Filters>
			<d3:InclinationFilter />
			<d3:FrequencyFilter />
		</d3:LineGraph.Filters>
	</d3:LineGraph>

	<d3:DefaultContextMenu />
</d3:ChartPlotter>

mike

 

<d3:ChartPlotter Name="plotter">
<d3:LineGraph DataSource="{Binding Data}">
<d3:LineGraph.Filters>
<d3:InclinationFilter />
<d3:FrequencyFilter />
</d3:LineGraph.Filters>
</d3:LineGraph>
<d3:DefaultContextMenu />
</d3:ChartPlotter>
Nov 9, 2009 at 4:43 AM
Edited Nov 9, 2009 at 4:54 AM

I played around a little more with this and think I found a decent solution.   First I tried to use an ItemsControl with a ChartPlotter ItemsPanel, but since ChartPlotter doesn't descend from Panel, that didn't work.  So I figured it would probably just be easier to write a ItemsControl-type chart.

The result is a new Control called ChartItemsControl that can be used to bind to a collection that is IEnumerable<IPlotterElement>.  This allows dynamic updating via a ViewModel of not only the line graphs but Context menu, mouse interaction, etc.  In addition, children can still be specified in the XAML view and be preserved across changes to ItemsSource.  Used something like this...

<d3:ChartItemsControl ItemsSource="{Binding Path=ChartChildren}">
  <d3:DefaultContextMenu />
</d3:ChartItemsControl>

I uploaded the path to codeplex, so take a look and see what you think.  I am still cleaning up a sample if that will be of assistance.

Thanks for a great library,

mike

 

Nov 18, 2009 at 4:12 PM

Hi Mike!

I'm looking exactly for that, take a look in my question: http://dynamicdatadisplay.codeplex.com/Thread/View.aspx?ThreadId=63633 (last reply as for 18/11/2009).

Could you please provide me the code?

Thanks a lot in advance,

André

Nov 18, 2009 at 4:52 PM
I moved away from having a separate control that did it and added it directly to the chart control, now you just
<ChartPlotter ItemsSource="{Binding Charts}" />

In the source directory under Stable\v0.3.1\src\DynamicDataDisplay\Common add the following code to the bottom of the Plotter class in Plotter.cs (sorry for the inline code, but I can't figure out how to do an attachment...)  Of course I have not rigorously tested it, but have been using this for a week or so and has held up so far.  Let me know if you have any problems and I'll see what I can do to fix them.

mike

#region Items Source

public static DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(Plotter), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Bindable(true)]
public IEnumerable ItemsSource
{
  get
  {
    return (IEnumerable)GetValue(ItemsSourceProperty);
  }
  set
  {
    if(value == null)
      ClearValue(ItemsSourceProperty);
    else
      SetValue(ItemsSourceProperty, value);
  }
}

private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  Plotter control = (Plotter)d;
  IEnumerable oldValue = (IEnumerable)e.OldValue;
  IEnumerable newValue = (IEnumerable)e.NewValue;

  if(e.NewValue == null)
    control.ClearItemsSource();
  else
    control.SetItemsSource(newValue);
}

private List<IPlotterElement> _elementsInItemsSource = new List<IPlotterElement>();
private IEnumerable _itemsSource = null;

private void ClearItemsSource()
{
  if(_itemsSource != null && _itemsSource is INotifyCollectionChanged)
    (_itemsSource as INotifyCollectionChanged).CollectionChanged -= ItemsSourceCollectionChanged;

  //remove the elements that were added from the items source (create a copy since RemoveItemSourceChild changes the enumeration)
  List<IPlotterElement> removes = new List<IPlotterElement>(_elementsInItemsSource);
  foreach(IPlotterElement elem in removes)
    RemoveItemSourceChild(elem);

  _elementsInItemsSource.Clear();
}

private void SetItemsSource(IEnumerable list)
{
  ClearItemsSource();

  foreach(object o in list)
  {
    if(o is IPlotterElement)
      AddItemSourceChild(o as IPlotterElement);
  }

  _itemsSource = list;
  if(_itemsSource is INotifyCollectionChanged)
    (_itemsSource as INotifyCollectionChanged).CollectionChanged += ItemsSourceCollectionChanged;
}

private void RemoveItemSourceChild(IPlotterElement elem)
{
  Children.Remove(elem);
  //it's not in the plotter anymore
  _elementsInItemsSource.Remove(elem);
}

private void AddItemSourceChild(IPlotterElement elem)
{
  Children.Add(elem);
  //it's in the plotter not
  _elementsInItemsSource.Add(elem);
}

private void ItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
  if(e.OldItems != null)
  {
    foreach(object o in e.OldItems)
    {
      if(o is IPlotterElement)
        RemoveItemSourceChild(o as IPlotterElement);
    }
  }

  if(e.NewItems != null)
  {
    foreach(object o in e.NewItems)
    {
      if(o is IPlotterElement)
        AddItemSourceChild(o as IPlotterElement);
    }
  }
}

#endregion


 

 

#region Items Source
public static DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(Plotter), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnItemsSourceChanged)));
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), Bindable(true)]
public IEnumerable ItemsSource
{
get
{
return (IEnumerable)GetValue(ItemsSourceProperty);
}
set
{
if(value == null)
ClearValue(ItemsSourceProperty);
else
SetValue(ItemsSourceProperty, value);
}
}
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Plotter control = (Plotter)d;
IEnumerable oldValue = (IEnumerable)e.OldValue;
IEnumerable newValue = (IEnumerable)e.NewValue;
if(e.NewValue == null)
control.ClearItemsSource();
else
control.SetItemsSource(newValue);
}
private List<IPlotterElement> _elementsInItemsSource = new List<IPlotterElement>();
private IEnumerable _itemsSource = null;
private void ClearItemsSource()
{
if(_itemsSource != null && _itemsSource is INotifyCollectionChanged)
(_itemsSource as INotifyCollectionChanged).CollectionChanged -= ItemsSourceCollectionChanged;
//remove the elements that were added from the items source (create a copy since RemoveItemSourceChild changes the enumeration)
List<IPlotterElement> removes = new List<IPlotterElement>(_elementsInItemsSource);
foreach(IPlotterElement elem in removes)
RemoveItemSourceChild(elem);
_elementsInItemsSource.Clear();
}
private void SetItemsSource(IEnumerable list)
{
ClearItemsSource();
foreach(object o in list)
{
if(o is IPlotterElement)
AddItemSourceChild(o as IPlotterElement);
}
_itemsSource = list;
if(_itemsSource is INotifyCollectionChanged)
(_itemsSource as INotifyCollectionChanged).CollectionChanged += ItemsSourceCollectionChanged;
}
private void RemoveItemSourceChild(IPlotterElement elem)
{
Children.Remove(elem);
//it's not in the plotter anymore
_elementsInItemsSource.Remove(elem);
}
private void AddItemSourceChild(IPlotterElement elem)
{
Children.Add(elem);
//it's in the plotter not
_elementsInItemsSource.Add(elem);
}
private void ItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if(e.OldItems != null)
{
foreach(object o in e.OldItems)
{
if(o is IPlotterElement)
RemoveItemSourceChild(o as IPlotterElement);
}
}
if(e.NewItems != null)
{
foreach(object o in e.NewItems)
{
if(o is IPlotterElement)
AddItemSourceChild(o as IPlotterElement);
}
}
}
#endregion

 

 

Dec 8, 2009 at 11:46 AM

Hi Mike,

Thanks a lot for the code, really appreciated.

Cheers,

André Carlucci