Example T541777
Visible to All Users

Chart for WPF - Bind a Chart to Its View Model

This example shows how to use the MVVM design pattern to create a multi-pane chart, and add a separate series, legend, and y-axis to each pane.

Resulting chart

To create chart elements from the ViewModel, use the ~ItemsSource property to bind the chart to a collection that contains element view models. Then, specify the element's ~ItemTemplate or ~ItemTemplateSelector to bind the element's properties to the element view model's properties.

For example, to create chart legends, use the ChartControlBase.LegendItemsSource and ChartControlBase.LegendItemTemplate properties.

Files to Review

Documentation

More Examples

Does this example address your development requirements/objectives?

(you will be redirected to DevExpress.com to submit your response)

Example Code

MvvmSample/View/MainWindow.xaml
XAML
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MvvmSample" xmlns:viewModel="clr-namespace:MvvmSample.ViewModel" xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts" x:Class="MvvmSample.MainWindow" mc:Ignorable="d" Title="MainWindow" Height="405" Width="720"> <Window.DataContext> <viewModel:MainViewModel/> </Window.DataContext> <Grid> <dxc:ChartControl DataSource="{Binding DataProvider.WeatherInfos}" LegendItemsSource="{Binding Chart.Legends}"> <dxc:ChartControl.CrosshairOptions> <dxc:CrosshairOptions ShowOnlyInFocusedPane="False" GroupHeaderPattern="{}{A:d MMMM, hh:mm}"/> </dxc:ChartControl.CrosshairOptions> <dxc:ChartControl.Titles> <dxc:Title Content="Weather in London" HorizontalAlignment="Center"/> </dxc:ChartControl.Titles> <dxc:XYDiagram2D SeriesItemsSource="{Binding Chart.Series}" SecondaryAxisYItemsSource="{Binding Chart.YAxes}" PaneItemsSource="{Binding Chart.Panes}" EnableAxisXNavigation="True"> <dxc:XYDiagram2D.DefaultPane> <dxc:Pane Visibility="Collapsed"/> </dxc:XYDiagram2D.DefaultPane> <dxc:XYDiagram2D.AxisX> <dxc:AxisX2D VisibilityInPaneItemsSource="{Binding Chart.Panes}" GridLinesMinorVisible="True" GridLinesVisible="True" Interlaced="True"> <dxc:AxisX2D.VisualRange> <dxc:Range MinValue="{Binding Chart.XAxis.MinValue}" MaxValue="{Binding Chart.XAxis.MaxValue}"/> </dxc:AxisX2D.VisualRange> <dxc:AxisX2D.DateTimeScaleOptions> <dxc:ManualDateTimeScaleOptions MeasureUnit="Hour" GridAlignment="Hour"/> </dxc:AxisX2D.DateTimeScaleOptions> <dxc:AxisX2D.VisibilityInPaneItemTemplate> <DataTemplate> <ContentControl> <dxc:VisibilityInPane Pane="{Binding}" Visible="{Binding ShowXAxis}"/> </ContentControl> </DataTemplate> </dxc:AxisX2D.VisibilityInPaneItemTemplate> </dxc:AxisX2D> </dxc:XYDiagram2D.AxisX> <dxc:XYDiagram2D.AxisY> <dxc:AxisY2D Visible="False" GridLinesVisible="False" GridLinesMinorVisible="False" Interlaced="False"/> </dxc:XYDiagram2D.AxisY> <dxc:XYDiagram2D.SeriesItemTemplateSelector> <local:SeriesTypeTemplateSelector> <local:SeriesTypeTemplateSelector.AreaTemplate> <DataTemplate> <dxc:AreaSeries2D DisplayName="{Binding Name}" ArgumentDataMember="{Binding ArgumentName}" ValueDataMember="{Binding ValueName}" Legend="{Binding Legend}" Pane="{Binding Pane}" AxisY="{Binding YAxis}" CrosshairLabelPattern="{}{V}"/> </DataTemplate> </local:SeriesTypeTemplateSelector.AreaTemplate> <local:SeriesTypeTemplateSelector.BarTemplate> <DataTemplate> <dxc:BarSideBySideSeries2D DisplayName="{Binding Name}" ArgumentDataMember="{Binding ArgumentName}" ValueDataMember="{Binding ValueName}" Legend="{Binding Legend}" Pane="{Binding Pane}" AxisY="{Binding YAxis}" CrosshairLabelPattern="{}{V}" BarWidth="2"/> </DataTemplate> </local:SeriesTypeTemplateSelector.BarTemplate> <local:SeriesTypeTemplateSelector.LineTemplate> <DataTemplate> <dxc:LineSeries2D DisplayName="{Binding Name}" ArgumentDataMember="{Binding ArgumentName}" ValueDataMember="{Binding ValueName}" Legend="{Binding Legend}" Pane="{Binding Pane}" AxisY="{Binding YAxis}" CrosshairLabelPattern="{}{V}"/> </DataTemplate> </local:SeriesTypeTemplateSelector.LineTemplate> </local:SeriesTypeTemplateSelector> </dxc:XYDiagram2D.SeriesItemTemplateSelector> <dxc:XYDiagram2D.PaneItemTemplate> <DataTemplate> <dxc:Pane> <dxc:Pane.AxisXScrollBarOptions> <dxc:ScrollBarOptions Visible="{Binding ShowXAxis}"/> </dxc:Pane.AxisXScrollBarOptions> </dxc:Pane> </DataTemplate> </dxc:XYDiagram2D.PaneItemTemplate> <dxc:XYDiagram2D.SecondaryAxisYItemTemplate> <DataTemplate> <dxc:SecondaryAxisY2D Alignment="Near" GridLinesMinorVisible="True" GridLinesVisible="True" ConstantLineInFrontItemsSource="{Binding ConstantLines}"> <dxc:SecondaryAxisY2D.WholeRange> <dxc:Range dxc:AxisY2D.AlwaysShowZeroLevel="False"/> </dxc:SecondaryAxisY2D.WholeRange> <dxc:SecondaryAxisY2D.Title> <dxc:AxisTitle Content="{Binding Title}"/> </dxc:SecondaryAxisY2D.Title> <dxc:SecondaryAxisY2D.ConstantLineInFrontItemTemplate> <DataTemplate> <dxc:ConstantLine Value="{Binding Value}"> <dxc:ConstantLine.Title> <dxc:ConstantLineTitle Content="{Binding Title}"/> </dxc:ConstantLine.Title> </dxc:ConstantLine> </DataTemplate> </dxc:SecondaryAxisY2D.ConstantLineInFrontItemTemplate> </dxc:SecondaryAxisY2D> </DataTemplate> </dxc:XYDiagram2D.SecondaryAxisYItemTemplate> </dxc:XYDiagram2D> <dxc:ChartControl.LegendItemTemplate> <DataTemplate> <dxc:Legend DockTarget="{Binding DockTarget}" HorizontalPosition="Left" VerticalPosition="Top"/> </DataTemplate> </dxc:ChartControl.LegendItemTemplate> </dxc:ChartControl> </Grid> </Window>
MvvmSample/View/MainWindow.xaml.cs(vb)
C#
using MvvmSample.ViewModel; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace MvvmSample { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } } public class SeriesTypeTemplateSelector: DataTemplateSelector { public DataTemplate AreaTemplate { get; set; } public DataTemplate BarTemplate { get; set; } public DataTemplate LineTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { SeriesViewModel seriesVM = item as SeriesViewModel; if(seriesVM == null) return base.SelectTemplate(item, container); switch (seriesVM.Type) { case SeriesType.Area: return AreaTemplate; case SeriesType.Bar: return BarTemplate; case SeriesType.Line: return LineTemplate; default: return base.SelectTemplate(item, container); } } } }
MvvmSample/ViewModel/MainViewModel.cs(vb)
C#
using MvvmSample.Model; using System; using System.Linq; namespace MvvmSample.ViewModel { class MainViewModel { public ChartViewModel Chart { get; private set; } public WeatherProvider DataProvider { get; private set; } public MainViewModel() { DataProvider = new XmlWeatherProvider("Data/WeatherData.xml"); PaneViewModel temperaturePane = new PaneViewModel( showXAxis: false ); PaneViewModel pressurePane = new PaneViewModel( showXAxis: false ); PaneViewModel humidityPane = new PaneViewModel( showXAxis: true ); LegendViewModel temperatureLegend = new LegendViewModel(dockTarget: temperaturePane); LegendViewModel pressureLegend = new LegendViewModel(dockTarget: pressurePane); LegendViewModel humidityLegend = new LegendViewModel(dockTarget: humidityPane); XAxisViewModel xAxis = new XAxisViewModel { MinValue = DataProvider.WeatherInfos.First().Timestamp, MaxValue = DataProvider.WeatherInfos.ElementAt(10).Timestamp }; YAxisViewModel temperatureYAxis = new YAxisViewModel( title: "Temperature, F", constantLines: null ); YAxisViewModel pressureYAxis = new YAxisViewModel( title: "Pressure, mbar", constantLines: null ); YAxisViewModel humidityYAxis = new YAxisViewModel( title: "Humidity, %", constantLines: new ConstantLineViewModel[] { new ConstantLineViewModel( title: String.Empty, value: 60.0) } ); SeriesViewModel temperatureSeries = new SeriesViewModel( name: "Temperature", type: SeriesType.Line, argumentName: "Timestamp", valueName: "Temperature", legend: temperatureLegend, pane: temperaturePane, yAxis: temperatureYAxis ); SeriesViewModel pressureSeries = new SeriesViewModel( name: "Pressure", type: SeriesType.Area, argumentName: "Timestamp", valueName: "Pressure", legend: pressureLegend, pane: pressurePane, yAxis: pressureYAxis ); SeriesViewModel humiditySeries = new SeriesViewModel( name: "Humidity", type: SeriesType.Bar, argumentName: "Timestamp", valueName: "RelativeHumidity", legend: humidityLegend, pane: humidityPane, yAxis: humidityYAxis); Chart = new ChartViewModel( series: new SeriesViewModel[] { temperatureSeries, pressureSeries, humiditySeries }, panes: new PaneViewModel[] { temperaturePane, pressurePane, humidityPane }, xAxis: xAxis, yAxes: new YAxisViewModel[] { temperatureYAxis, pressureYAxis, humidityYAxis }, legends: new LegendViewModel[] { temperatureLegend, pressureLegend, humidityLegend } ); } } }
MvvmSample/ViewModel/ChartViewModel.cs(vb)
C#
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MvvmSample.ViewModel { class ChartViewModel { public IEnumerable<PaneViewModel> Panes { get; private set; } public XAxisViewModel XAxis { get; private set; } public IEnumerable<YAxisViewModel> YAxes { get; private set; } public IEnumerable<SeriesViewModel> Series { get; private set; } public IEnumerable<LegendViewModel> Legends { get; private set; } public ChartViewModel (IEnumerable<SeriesViewModel> series, IEnumerable<LegendViewModel> legends, IEnumerable<PaneViewModel> panes, XAxisViewModel xAxis, IEnumerable<YAxisViewModel> yAxes) { this.Series = series; this.XAxis = xAxis; this.YAxes = yAxes; this.Panes = panes; this.Legends = legends; } } class LegendViewModel { public PaneViewModel DockTarget { get; private set; } public LegendViewModel(PaneViewModel dockTarget) { this.DockTarget = dockTarget; } } class PaneViewModel { public bool ShowXAxis { get; private set; } public PaneViewModel(bool showXAxis) { this.ShowXAxis = showXAxis; } } class XAxisViewModel { public DateTime MinValue { get; set; } public DateTime MaxValue { get; set; } } class YAxisViewModel { public string Title { get; private set; } public IEnumerable<ConstantLineViewModel> ConstantLines { get; private set; } public YAxisViewModel(string title, IEnumerable<ConstantLineViewModel> constantLines) { this.Title = title; this.ConstantLines = constantLines; } } class SeriesViewModel { public string Name { get; set; } public string ArgumentName { get; private set; } public string ValueName { get; private set; } public LegendViewModel Legend { get; private set; } public PaneViewModel Pane { get; private set; } public YAxisViewModel YAxis { get; private set; } public SeriesType Type { get; private set; } public SeriesViewModel(string name, SeriesType type, string argumentName, string valueName, LegendViewModel legend, PaneViewModel pane, YAxisViewModel yAxis) { this.Name = name; this.Type = type; this.ArgumentName = argumentName; this.ValueName = valueName; this.Legend = legend; this.Pane = pane; this.YAxis = yAxis; } } class ConstantLineViewModel { public string Title { get; private set; } public double Value { get; private set; } public ConstantLineViewModel(string title, double value) { this.Title = title; this.Value = value; } } public enum SeriesType { Bar, Area, Line } }
MvvmSample/Model/WeatherInfo.cs(vb)
C#
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Globalization; using System.IO; using System.Xml.Linq; namespace MvvmSample.Model { class WeatherInfo { public DateTime Timestamp { get; private set; } public double Temperature { get; private set; } public int Pressure { get; private set; } public int RelativeHumidity { get; private set; } public WeatherInfo( DateTime timestamp, double temperature, int pressure, int relativeHumidity ) { this.Timestamp = timestamp; this.Temperature = temperature; this.Pressure = pressure; this.RelativeHumidity = relativeHumidity; } } interface WeatherProvider { IEnumerable<WeatherInfo> WeatherInfos { get; } } class XmlWeatherProvider : WeatherProvider { string filename; public XmlWeatherProvider(string filename) { if (File.Exists(filename)) { this.filename = filename; } else { throw new Exception(String.Format("The \'{0}\' file does not exist.", filename)); } } Collection<WeatherInfo> infos; public IEnumerable<WeatherInfo> WeatherInfos { get { if(infos == null) { XDocument doc = XDocument.Load(filename); infos = new Collection<WeatherInfo>(); foreach (XElement element in doc.Element("WeatherData").Elements("WeatherInfo")) { infos.Add(new WeatherInfo( timestamp: DateTime.Parse(element.Element("Timestamp").Value, CultureInfo.InvariantCulture), temperature: double.Parse(element.Element("Temperature").Value, CultureInfo.InvariantCulture), pressure: int.Parse(element.Element("Pressure").Value, CultureInfo.InvariantCulture), relativeHumidity: int.Parse(element.Element("RelativeHumidity").Value, CultureInfo.InvariantCulture) )); } } return infos; }} } }

Disclaimer: The information provided on DevExpress.com and affiliated web properties (including the DevExpress Support Center) is provided "as is" without warranty of any kind. Developer Express Inc disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.

Confidential Information: Developer Express Inc does not wish to receive, will not act to procure, nor will it solicit, confidential or proprietary materials and information from you through the DevExpress Support Center or its web properties. Any and all materials or information divulged during chats, email communications, online discussions, Support Center tickets, or made available to Developer Express Inc in any manner will be deemed NOT to be confidential by Developer Express Inc. Please refer to the DevExpress.com Website Terms of Use for more information in this regard.