4

I'm working on a WPF app. This app uses the OxyPlot chart control. I am letting the user perform a calculation. The user can view the result in both grid and chart form. In an attempt to do this, I have the following:

home.xaml

<DataGrid x:Name="resultDataGrid" ItemsSource="{Binding Items}">
  <DataGrid.Columns>
    <DataGridTextColumn Header="#" Binding="{Binding Number}" />
    <DataGridTextColumn Header="Description" Binding="{Binding Description}" />
  </DataGrid.Columns>
</DataGrid>

<oxy:Plot x:Name="resultGraph" Background="Transparent" Height="400" HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch" Visibility="Collapsed">
  <oxy:Plot.Series>
    <oxy:LineSeries ItemsSource="{Binding Points}" MarkerType="Circle"  Title="Result" />
  </oxy:Plot.Series>
</oxy:Plot>

<StackPanel Orientation="Horizontal">
  <Button x:Name="executeButton" Click="executeButton_Click" />
  <Button x:Name="viewData" Click="viewData_Click" />
  <Button x:Name="viewChart" Click="viewChart_Click" />
</StackPanel>

home.xaml.cs

public partial class Home: Page
{
  private MyViewModel viewModel = null;
  public Home()
  {
    InitializeComponent();

    viewModel = new MyViewModel();
    this.DataContext = viewModel;
  }

  private void executeButton_Click(object sender, RoutedEventArgs e) {
    viewModel.Execute();
  }

  private void viewData_Click(object sender, RoutedEventArgs e) 
  {
    resultDataGrid.Visibility = System.Windows.Visibility.Visible;
    resultGraph.Visibility = System.Windows.Visibility.Collapsed;
  }

  private void viewChart_Click(object sender, RoutedEventArgs e)
  {
    resultDataGrid.Visibility = System.Windows.Visibility.Collapsed;
    resultGraph.Visibility = System.Windows.Visibility.Visible;
  }
}

MyViewModel.cs

public class MyViewModel : INotifyPropertyChanged
{
  public Dictionary<int, string> Items{ get; set; }
  public IList<DataPoint> Points{ get; set; }

  public void Execute() 
  {
    this.Items = new Dictionary<int, string>();
    this.Points = new List<DataPoint>();

    var randomNumber = GetRandomNumber();
    for (var i=0; i<10; i++) 
    {
      this.Items.Add((i+1), "Item #" + i);

      var dataPoint = new DataPoint(i, (randomNumber*i));
      this.Points.Add(dataPoint);
    }

    NotifyPropertyChanged("Items");
    NotifyPropertyChanged("Points");
  }
}

My problem is, when a user clicks the "Execute" button, the data gets refreshed for in the DataGrid, which is what I am expecting. However, the chart only gets refreshed if the chart is first visible. In other words, if I click "execute" when the DataGrid is visible, the plot points in the chart become stale. But, If I have the resultGraph visible and I click "Execute" the points get refreshed as expected. I do not understand what I'm doing wrong. Any help is appreciated.

user70192
  • 13,786
  • 51
  • 160
  • 240
  • If plot is not updated then more likely due to missing notification. Check for typos in property name (using `NotifyPropertyChanged(nameof(Points))` is preferable as compiler will do a check). Perhaps there is a special way to update plots, try to find such method (`Refresh`?). Check if your idea of visibility change is correct one by changing visibility (of series? of plot?). – Sinatr Feb 16 '16 at 13:52
  • Please see ["Should questions include “tags” in their titles?"](http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles), where the consensus is "no, they should not"! –  Feb 16 '16 at 15:58

3 Answers3

3

in your ViewModel create

private int _invalidateFlag = 0;
public int InvalidateFlag
{
   get {return _invalidateFlag;}
   set
   {
      _invalidateFlag = value;
      NotifyPropertyChanged();
   }
}

//and to the end of Execute() add

InvalidateFlag++;

also don't forget to bind the InvalidateFlag

<oxy:Plot x:Name="resultGraph" InvalidateFlag="{Binding InvalidateFlag}" Background="Transparent" Height="400" HorizontalContentAlignment="Stretch" VerticalAlignment="Stretch" Visibility="Collapsed">

this should do the trick

kulhajs
  • 132
  • 7
1

Actually I found the answer here:

OxyPlot is not observing property or collection changes. This means that the client application is responsible for refreshing the plot when the content has changed.

You have to invalidate plot after you do change. There are several possibilities.

Easiest probably is a dirty MVVM: in view subscribe to viewmodel PropertyChanged event, check if this event rised by Points changed and invalidate plot.

Sinatr
  • 20,892
  • 15
  • 90
  • 319
1

Normally OxyPlot provides the method PlotModel.InvalidatePlot(true) to refresh a chart with the new input data. Edit: Oh I saw you have no PlotModel property in your ViewModel. My answer needs such a property which can be bind to the xaml too.