New to WPF and not sure how to programmatically instantiate a new viewmodel that wraps a new chart and its data collection. Right now, it consists of the following, but not sure the optimal way to set it up.
class ChartViewModel
{
public ChartViewModel()
{
CartesianChart chart = new CartesianChart();
chart.Series = new SeriesCollection
{
new GLineSeries
{
Title = "Pressure",
Values = new GearedValues<double>(),
},
new GLineSeries
{
Title = "Pulse",
Values = new GearedValues<int>(),
}
};
}
}
And then, I need to add the new chart to the view. The CartesianChart object is the UIElement and it works as follows when I just test it in main window without this class.
stackPanel.Children.Add(chart);
But the class can't access the xaml it seems and I can't add the actual view model class since thats not a UIElement, only the chart is. Basically need to create a new chart instance every time the previous chart fills up with something like this:
ChartViewModel tempChart = new ChartViewModel();
chartRepo.Add(tempChart); //chart repo is a list of ChartViewModels
So it needs its own SeriesCollection and UIElement. Thanks for any recommendations.
If you want to dynamically add new charts you have to make use of DataTemplate
to template the chart data.
The DataTemplate
which consists of the chart is bound to a ChartDataModel
. We can use a ListView
to display the charts (data templates). A view model ChartViewModel
serves as the ListView.ItemsSource
and holds a set of ChartData
.
Each ChartData
maps to a new chart.
Whenever you create a new ChartDataModel
in the ChartViewModel
and add it to ChartModels
, the ListView
will automatically create a new chart.
The view:
<ListView ItemsSource="{Binding ChartModels}">
<ListView.DataContext>
<ChartViewModel />
</ListView.DataContext>
<ListView.ItemTemplate>
<DataTemplate DataType="ChartDataModel">
<CartesianChart>
<CartesianChart.Series>
<LineSeries Title="Pressure" Values="{Binding PressureValues}" />
<LineSeries Title="Pulse" Values="{Binding PulseValues}" />
</CartesianChart.Series>
</CartesianChart>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The model:
class ChartDataModel
{
public ChartDataModel()
{
this.PressureValues = new ChartValues<double>();
this.PulseValues = new ChartValues<double>();
}
public ChartValues<double> PressureValues { get; set; }
public ChartValues<double> PulseValues { get; set; }
}
The view model:
class ChartViewModel : INotifyPropertyChanged
{
public ChartViewModel()
{
this.ChartModels = new ObservableCollection<ChartDataModel>();
CreateNewChart();
}
private void CreateNewChart()
{
var newChartDataModel = new ChartDataModel()
{
PressureDataValues = new ChartValues<double>()
{
10, 20, 30, 40, 50
},
PulseDataValues = new ChartValues<double>()
{
100, 200, 300, 400, 500
}
};
this.ChartModels.Add(newChartDataModel);
}
private ObservableCollection<ChartDataModel> chartModels;
public ObservableCollection<ChartDataModel> ChartModels
{
get => this.chartModels;
set
{
if (Equals(value, this.chartModels)) return;
this.chartModels = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}