From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.
We appreciate your patience as we improve our online experience.
From Friday, April 19th (11:00 PM CDT) through Saturday, April 20th (2:00 PM CDT), 2024, ni.com will undergo system upgrades that may result in temporary service interruption.
We appreciate your patience as we improve our online experience.
01-04-2018 09:47 AM - edited 01-04-2018 10:09 AM
I don't know how many plots I need to graph at runtime, so I make a WPF Graph DataSource binding to a collection of a collection of points. The graph binding works fine when I have more than 1 collection of points (i.e. 2 collections and 2 plots), but I cannot get the graph to bind when there is only one collection of points. Should this work, or is this approach way off base?
Binding Object:
private ObservableCollection<ObservableCollection<System.Windows.Point>> _PlotXYData = new ObservableCollection<ObservableCollection<System.Windows.Point>>(); public ObservableCollection<ObservableCollection<System.Windows.Point>> PlotXYData { get { return _PlotXYData; } set { _PlotXYData = value; RaisePropertyChanged("PlotXYData"); } }
XAML Binding:
<ni:Graph Name="graph1" DataSource="{Binding Path=ViewModel.PlotXYData}"> <ni:Graph.Axes> <ni:AxisDouble x:Name="HorizontalAxis1" Orientation="Horizontal" Range="{Binding Path=ViewModel.NIGraph.Axes[0].Range}" Adjuster="FitLoosely" > </ni:AxisDouble> <ni:AxisDouble x:Name="VerticalAxis1" Orientation="Vertical" Range="{Binding Path=ViewModel.NIGraph.Axes[1].Range}" Adjuster="FitLoosely"> </ni:AxisDouble> <ni:AxisDouble x:Name="VerticalAxis2" Orientation="Vertical" Range="{Binding Path=ViewModel.NIGraph.Axes[2].Range}" Adjuster="FitLoosely" Location="Far" MajorGridLines="{x:Null}"> </ni:AxisDouble> </ni:Graph.Axes> <ni:Graph.Plots> <ni:Plot Label="Plots[0]" VerticalScale="{Binding ElementName=VerticalAxis1}" > <ni:LinePlotRenderer Stroke="#FF0070B0" /> </ni:Plot> <ni:Plot Label="Plots[1]" VerticalScale="{Binding ElementName=VerticalAxis2}" > <ni:LinePlotRenderer Stroke="#FFB90E30" /> </ni:Plot> </ni:Graph.Plots> </ni:Graph>
Solved! Go to Solution.
01-04-2018 10:34 AM
one more thing to add... if the collection is only 1 collection of points, then it works if I bind as follows:
<ni:Graph Name="graph1" DataSource="{Binding Path=ViewModel.PlotXYData[0]}">
01-04-2018 01:53 PM
I could not reproduce the issue you are seeing, using your XAML and this simplified test code:
public partial class MainWindow : Window { private readonly ViewModel _viewModel = new ViewModel( ); public MainWindow( ) { DataContext = new { ViewModel = _viewModel }; InitializeComponent( ); var button = new Button { HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Bottom, Content = "_Add Point" }; button.Click += OnAddPointClicked; var grid = (Grid)Content; grid.Children.Add( button ); } private void OnAddPointClicked( object sender, RoutedEventArgs e ) { if( _viewModel.PlotXYData.Count == 0 ) { _viewModel.PlotXYData.Add( new ObservableCollection<Point>( ) ); } else { var points = _viewModel.PlotXYData[0]; do { points.Add( new Point( points.Count, points.Count * points.Count ) ); } while( points.Count < 2 ); } } class ViewModel { private ObservableCollection<ObservableCollection<Point>> _PlotXYData = new ObservableCollection<ObservableCollection<Point>>( ); public ObservableCollection<ObservableCollection<Point>> PlotXYData { get { return _PlotXYData; } } } }
As I click the “Add Point” button repeatedly, I see the point collection get added on the first click (in the debugger), and the points appear on further clicks.
Could you provide a simple application that reproduces the problem?
01-05-2018 08:40 AM
No! I can't. Because it does work. Thanks for the example, Paul. I should have tried something small to verify before I posted.
My problem had something do to with how I was updating the inner ObservableCollection after the binding was setup. I have run into this before, and I think it is related to how an item that is added to a List (or ObservableCollection) may not actually notify the binding. Updating the entire ObservableCollection, in this case, does indeed notify the binding, so I have to study that a little more.
After I saw your working example, I thought maybe my problem was that I wrapped the graph in a WPF User Control and passed the ViewModel to the UserControl at runtime. As it turns out, this also works. This is an interesting approach, and although my coding is not great, I'll add it here in case anyone wants to take advantage of this kind of approach with Measurement Studio WPF controls in the future.
Thanks again!
01-05-2018 08:46 AM
...just to add a little detail. In my code, this does not update the graph binding to PlotXYData:
p.X = PlotXYData[0].Last().X + IncrementX; p.Y = ValueY; PlotXYData[0].Add(p);
but THIS does!
p.X = PlotXYData[0].Last().X + IncrementX; p.Y = ValueY; PlotXYData[0].Add(p); PlotXYData[0] = PlotXYData[0];
01-05-2018 08:53 AM
...because I was implementing RaisePropertyChanged on the collection, not the children. I need to look at this a little more, but this is the crux of it.