{"id":1733,"date":"2013-02-16T16:46:33","date_gmt":"2013-02-16T16:46:33","guid":{"rendered":"https:\/\/www.scichart.com\/2013\/02\/16\/databinding-annotations-with-mvvm\/"},"modified":"2022-12-09T13:09:07","modified_gmt":"2022-12-09T13:09:07","slug":"databinding-annotations-with-mvvm","status":"publish","type":"post","link":"https:\/\/www.scichart.com\/databinding-annotations-with-mvvm\/","title":{"rendered":"Databinding Annotations with MVVM"},"content":{"rendered":"

This page is out of date. To see the latest guide, please go to the updated documentation<\/a><\/p><\/blockquote>\n

Annotations with MVVM<\/h2>\n

An often requested demonstration is how to add and remove annotations on a SciChartSurface using the MVVM pattern. MVVM is a great way to split your code into View (user interface) and business logic, to create decoupled, testable and maintainable applications.<\/p>\n

It\u2019s easy to forget sometimes the purpose of MVVM (or any pattern) is to simplify software development and decouple modules, making for more maintainable software, when sometimes we do exactly the opposite in order to meet a rule! This article will demonstrate a way we can bind annotations to viewmodels without compromising MVVM, or introducing any nasty hacks just to make it happen.<\/p>\n

So here it is! Let’s get started. You will need to download and install SciChart v1.5.x<\/a> for this.<\/p>\n

Creating the Solution<\/h3>\n

First lets start by creating a Visual Studio solution. Here at SciChart we use VS2012, however VS2010 is also supported.<\/p>\n

Create a new WPF project in your chosen IDE and add a reference to SciChart WPF. You can find the libraries under C:\/Program Files (x86)\/ABT Software Services\/SciChart\/Lib\/<\/p>\n

\"\"<\/a>
Referencing SciChart WPF from Program Files<\/figcaption><\/figure>\n

Now with the solution created, add a SciChartSurface to the MainWindow.xaml. It should build at this point. If not, double check your references, the target .NET framework and xmlns namespace declarations.<\/p>\n

\"\"<\/a>
Creating the SciChartSurface in Xaml. It should look like this!<\/figcaption><\/figure>\n

Now lets add some Axes to the chart. We will assign a VisibleRange and GrowBy properties, plus assign a theme to cause the chart to paint itself in the designer.<\/p>\n

<Window x:Class=\"AnnotationsMvvm.MainWindow\"\r\n             \r\n             xmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\"\r\n             xmlns:mc=\"http:\/\/schemas.openxmlformats.org\/markup-compatibility\/2006\" \r\n             xmlns:d=\"http:\/\/schemas.microsoft.com\/expression\/blend\/2008\" \r\n             xmlns:s=\"clr-namespace:Abt.Controls.SciChart;assembly=Abt.Controls.SciChart.Wpf\" \r\n             xmlns:local=\"clr-namespace:AnnotationsMvvm\" \r\n             mc:Ignorable=\"d\" \r\n             d:DesignHeight=\"480\" d:DesignWidth=\"640\">\r\n\r\n    <Grid>\r\n\r\n      <!-- Note, we're using the new MVVM SeriesSource API in v1.5 -->\r\n      <s:SciChartSurface SeriesSource=\"{Binding ChartSeries}\" s:ThemeManager.Theme=\"Chrome\">\r\n\r\n        <s:SciChartSurface.XAxis>\r\n          <s:NumericAxis VisibleRange=\"0,100\"\/>\r\n        <\/s:SciChartSurface.XAxis>\r\n\r\n        <s:SciChartSurface.YAxis>\r\n          <s:NumericAxis VisibleRange=\"-5,5\"\/>\r\n        <\/s:SciChartSurface.YAxis>\r\n\r\n      <\/s:SciChartSurface>\r\n    <\/Grid>\r\n<\/Window><\/pre>\n

You should now be looking at something a little like this:<\/p>\n

\"\"<\/a>
After adding Axes to the Chart, it should look like this in the designer<\/figcaption><\/figure>\n

Adding a MainViewModel<\/h3>\n

The MainViewModel is going to be the controller \/ data-provider for the MainWindow in this example. It is going to provide chart data, series colors and data-objects for the annotations.<\/p>\n

Here\u2019s the code for the MainViewModel in entirety. In a moment we will walk through the code to explain it.<\/p>\n

namespace AnnotationsMvvm\r\n{\r\n    public class MainViewModel : INotifyPropertyChanged\r\n    {\r\n        private ObservableCollection<IChartSeriesViewModel> _chartSeries;\r\n        private IEnumerable<LabelViewModel> _chartLabels;\r\n\r\n        \/\/ I'll leave it to you to wire up PropertyChanged to your base viewmodel type\r\n        public event PropertyChangedEventHandler PropertyChanged;\r\n\r\n        public MainViewModel()\r\n        {\r\n            var ds0 = new XyDataSeries<double, double>();\r\n\r\n            \/\/ RandomWalkGenerator is found in the examples source code\r\n            var someData = new RandomWalkGenerator().GetRandomWalkSeries(100); \r\n\r\n            ds0.Append(someData.XData, someData.YData);\r\n\r\n            \/\/ With SeriesSource API you do not need a DataSet. This is created automatically to match\r\n            \/\/ the type of DataSeries<Tx,Ty>. All DataSeries must be the same type however\r\n\r\n            \/\/ Create a list of ChartSeriesViewModel which unify dataseries and render series\r\n            \/\/ This way you can add\/remove your series and change the render series type easily\r\n            \/\/ without worrying about DataSeriesIndex as per SciChart v1.3\r\n            _chartSeries = new ObservableCollection<IChartSeriesViewModel>();\r\n            _chartSeries.Add(new ChartSeriesViewModel(ds0, new FastLineRenderableSeries()));\r\n\r\n            \/\/ Now create the labels\r\n            _chartLabels = new[]\r\n                               {\r\n                                   new LabelViewModel(5, -2.5, \"Label0\", \"Label0 Tooltip!\"), \r\n                                   new LabelViewModel(20, -2, \"Label1\", \"Label1 Tooltip!\"), \r\n                                   new LabelViewModel(35, 3, \"Label2\", \"Label2 Tooltip!\"), \r\n                                   new LabelViewModel(50, 1.5, \"Label3\", \"Label3 Tooltip!\"), \r\n                                   new LabelViewModel(65, -0.5, \"Label4\", \"Label4 Tooltip!\"), \r\n                               };\r\n        }\r\n\r\n        public ObservableCollection<IChartSeriesViewModel> ChartSeries { get { return _chartSeries; }}\r\n\r\n        public IEnumerable<LabelViewModel> ChartLabels { get { return _chartLabels; } }\r\n    }\r\n}<\/pre>\n

 <\/p>\n

Breaking this down, what we do is first create an XyDataSeries. This stores X-Y values in an optimized data structure that SciChart can consume. We append a Random Walk (randomly generated time series).<\/p>\n

 <\/p>\n

var ds0 = new XyDataSeries<double, double>();\r\n\r\n\/\/ RandomWalkGenerator is found in the examples source code\r\nvar someData = new RandomWalkGenerator().GetRandomWalkSeries(100); \r\n\r\nds0.Append(someData.XData, someData.YData);<\/pre>\n

You should note the XyDataSeries expects data to be sorted in the X-Direction. This is to enable fast indexing of the data when zooming and panning. If you want to add unsorted data-values then you should check out the UnsortedXyDataSeries.<\/p>\n

Also note that the RandomWalkGenerator class can be found in the examples source code contained in the SciChart Trial Installer.<\/p><\/blockquote>\n

The next part we create a collection of ChartSeriesViewModels. SciChart can bind to these in an MVVM context from the SeriesSource property<\/p>\n

 <\/p>\n

\/\/ With SeriesSource API you do not need a DataSet. This is created automatically to match\r\n\/\/ the type of DataSeries<Tx,Ty>. All DataSeries must be the same type however\r\n\r\n\/\/ Create a list of ChartSeriesViewModel which unify dataseries and render series\r\n\/\/ This way you can add\/remove your series and change the render series type easily\r\n\/\/ without worrying about DataSeriesIndex as per SciChart v1.3\r\n_chartSeries = new ObservableCollection<IChartSeriesViewModel>();\r\n_chartSeries.Add(new ChartSeriesViewModel(ds0, new FastLineRenderableSeries()));<\/pre>\n

 <\/p>\n

In the above code we create an ObservableCollection of IChartSeriesViewModel. This is a viewmodel type defined in the SciChart library, which unifies a DataSeries and RenderableSeries. The DataSeries has already been filled with data. I won\u2019t go too much into detail of the SeriesSource API, save to say there are plenty of MVVM demos on our website which show how to use this API.<\/p>\n

 <\/p>\n

Creating Annotation ViewModels<\/h3>\n

This next part is interesting. Here we define and expose an ObservableCollection of annotation view models.<\/p>\n

 <\/p>\n

\/\/ Inside MainViewModel, we now create the labels\r\n_chartLabels = new[]\r\n{\r\nnew LabelViewModel(5, -2.5, \"Label0\", \"Label0 Tooltip!\"), \r\nnew LabelViewModel(20, -2, \"Label1\", \"Label1 Tooltip!\"), \r\nnew LabelViewModel(35, 3, \"Label2\", \"Label2 Tooltip!\"), \r\nnew LabelViewModel(50, 1.5, \"Label3\", \"Label3 Tooltip!\"), \r\nnew LabelViewModel(65, -0.5, \"Label4\", \"Label4 Tooltip!\"), \r\n};\r\n\/\/ ...\r\npublic IEnumerable<LabelViewModel> ChartLabels { get { return _chartLabels; } }<\/pre>\n

 <\/p>\n

Where is LabelViewModel defined? This is a custom class created for this tutorial. Basically you just need to create a class, ensure it implements INotifyPropertyChanged, and has some properties to define the position and labels. Here is the LabelViewModel class in entirety:<\/p>\n

 <\/p>\n

public class LabelViewModel : INotifyPropertyChanged\r\n{\r\n    public event PropertyChangedEventHandler PropertyChanged;\r\n\r\n    public LabelViewModel(IComparable x1, IComparable y1, string text, string tooltip)\r\n    {\r\n        X1 = x1;\r\n        Y1 = y1;\r\n        LabelText = text;\r\n        LabelToolTip = tooltip;\r\n    }\r\n\r\n    \/\/\/ <summary>\r\n    \/\/\/ LabelText will allow us to bind to TextAnnotation.Text\r\n    \/\/\/ <\/summary>\r\n    public string LabelText { get; set; }\r\n\r\n    \/\/\/ <summary>\r\n    \/\/\/ LabelTooltip will be used to add a custom tooltip to the TextAnnotation\r\n    \/\/\/ <\/summary>\r\n    public string LabelToolTip { get; set; }\r\n\r\n    \/\/\/ <summary>\r\n    \/\/\/ X1 defines the X Data-Value for positioning the annotation\r\n    \/\/\/ <\/summary>\r\n    public IComparable X1 { get; set; }\r\n\r\n    \/\/\/ <summary>\r\n    \/\/\/ Y1 defines the Y Data-Value for positioning the annotation\r\n    \/\/\/ <\/summary>\r\n    public IComparable Y1 { get; set; }\r\n}<\/pre>\n

Running the Application so far<\/h3>\n

Ok, so to run the example and see some data in the chart, we need to ensure an instance of the MainViewModel is set on the chart. Add this XAML to the top of your MainWindow.xaml file.<\/p>\n

<Window x:Class=\"AnnotationsMvvm.MainWindow\"\r\n             \r\n             xmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2006\/xaml\"\r\n             xmlns:mc=\"http:\/\/schemas.openxmlformats.org\/markup-compatibility\/2006\" \r\n             xmlns:d=\"http:\/\/schemas.microsoft.com\/expression\/blend\/2008\" \r\n             xmlns:s=\"clr-namespace:Abt.Controls.SciChart;assembly=Abt.Controls.SciChart.Wpf\" \r\n             xmlns:local=\"clr-namespace:AnnotationsMvvm\" \r\n             mc:Ignorable=\"d\" \r\n             d:DesignHeight=\"480\" d:DesignWidth=\"640\">\r\n\r\n    <Window.Resources>\r\n        <local:MainViewModel x:Key=\"viewModel\"\/>\r\n    <\/Window.Resources>\r\n\r\n    <Grid DataContext=\"{StaticResource viewModel}\">\r\n\r\n      <s:SciChartSurface SeriesSource=\"{Binding ChartSeries}\" \r\n              <!-- Omitted for brevity ... -->\r\n      <\/s:SciChartSurface>\r\n    <\/Grid>\r\n<\/Window><\/pre>\n

 <\/p>\n

Now, if you run the application so far, you should see something like this:<\/p>\n

\"How<\/a>
How the Application Looks now – we should see a Line Chart<\/figcaption><\/figure>\n
\"You<\/a>
You should even see the line chart in the designer view!<\/figcaption><\/figure>\n

 <\/p>\n

You should even see the data in the designer, because the ViewModel bindings are evaluated at design time. Isn\u2019t that neat!?<\/p>\n


\nDon\u2019t see it? Here are some tips to debug why the chart is not showing:<\/em><\/p>\n