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.

Measurement Studio for .NET Languages

cancel
Showing results for 
Search instead for 
Did you mean: 

WPF Graph DataSource

Solved!
Go to solution

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>

 

0 Kudos
Message 1 of 6
(3,105 Views)

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]}">
0 Kudos
Message 2 of 6
(3,093 Views)
Solution
Accepted by topic author wrmbrnr

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?

~ Paul H
0 Kudos
Message 3 of 6
(3,082 Views)

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!

0 Kudos
Message 4 of 6
(3,056 Views)

...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];
0 Kudos
Message 5 of 6
(3,055 Views)

...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.

0 Kudos
Message 6 of 6
(3,053 Views)