Back to Devexpress

How to: Implement Selection in the MVVM Style

wpf-115265-controls-and-libraries-charts-suite-chart-control-examples-end-user-interaction-how-to-implement-selection-in-the-mvvm-style.md

latest16.4 KB
Original Source

How to: Implement Selection in the MVVM Style

  • Jun 07, 2019
  • 6 minutes to read

To implement a selection in the MVVM style, enable the selection feature using the ChartControl.SelectionMode property. Set this property to a value different from None.

Then, use the ChartControl.SelectedItem property to set or get a single selected view model object, or the ChartControl.SelectedItems property to set or get several view model objects.

xaml
<Window xmlns:dxm="http://schemas.devexpress.com/winfx/2008/xaml/map"  
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
        xmlns:dxc="http://schemas.devexpress.com/winfx/2008/xaml/charts"
        Title="MainWindow" Height="720" Width="1280"
        x:Class="MVVM_Selection.MainWindow"
        dx:ThemeManager.Theme="Office2013">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="3*"/>
            <ColumnDefinition Width="2*"/>
        </Grid.ColumnDefinitions>

        <dxc:ChartControl Grid.Column="0" 
                          Margin="4,4,2,4"
                          SelectionMode="Single"
                          SelectedItem="{Binding Path=SelectedCountry, Mode=TwoWay}">
            <dxc:ChartControl.Palette>
                <dxc:Office2013Palette/>
            </dxc:ChartControl.Palette>
            <dxc:ChartControl.Titles>
                <dxc:Title Content="Top 10 Countries By Area"
                           HorizontalAlignment="Center"/>
            </dxc:ChartControl.Titles>
            <dxc:ChartControl.Legend>
                <dxc:Legend HorizontalPosition="LeftOutside" 
                            VerticalPosition="Top"
                            Orientation="Vertical" IndentFromDiagram="2"/>
            </dxc:ChartControl.Legend>
            <dxc:SimpleDiagram2D>
                <dxc:PieSeries2D DataSource="{Binding Path=CountriesData}"
                                 ArgumentDataMember="Name"
                                 ValueDataMember="Area"
                                 LegendTextPattern="{}{A}">
                    <dxc:PieSeries2D.Model>
                        <dxc:BorderlessFlatPie2DModel/>
                    </dxc:PieSeries2D.Model>
                </dxc:PieSeries2D>
            </dxc:SimpleDiagram2D>
        </dxc:ChartControl>

        <dxc:ChartControl Grid.Column="1"
                          Margin="2,4,4,4">
            <dxc:ChartControl.Palette>
                <dxc:Office2013Palette/>
            </dxc:ChartControl.Palette>
            <dxc:ChartControl.Titles>
                <dxc:Title Content="{Binding Path=SelectedCountry.Name, Mode=OneWay}"
                           HorizontalAlignment="Center"/>
            </dxc:ChartControl.Titles>
            <dxc:XYDiagram2D>
                <dxc:XYDiagram2D.AxisX>
                    <dxc:AxisX2D>
                        <dxc:AxisX2D.WholeRange>
                            <dxc:Range AutoSideMargins="False" SideMarginsValue="0"/>
                        </dxc:AxisX2D.WholeRange>
                    </dxc:AxisX2D>
                </dxc:XYDiagram2D.AxisX>
                <dxc:XYDiagram2D.AxisY>
                    <dxc:AxisY2D>
                        <dxc:AxisY2D.WholeRange>
                            <dxc:Range dxc:AxisY2D.AlwaysShowZeroLevel="False"/>
                        </dxc:AxisY2D.WholeRange>
                        <dxc:AxisY2D.Title>
                            <dxc:AxisTitle Content="Population, millons"/>
                        </dxc:AxisY2D.Title>
                    </dxc:AxisY2D>
                </dxc:XYDiagram2D.AxisY>
                <dxc:AreaSeries2D DataSource="{Binding Path=SelectedCountry.PopulationDynamics}"
                                  ArgumentDataMember="Year"
                                  ValueDataMember="Population"/>
            </dxc:XYDiagram2D>
        </dxc:ChartControl>
    </Grid>
</Window>
vb
Imports MVVM_Selection.Model
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Globalization
Imports System.Xml.Linq

Namespace MVVM_Selection.ViewModel
    Public Class DashboardViewModel
        Implements INotifyPropertyChanged

        Private Shared instance_Renamed As DashboardViewModel

        Private ReadOnly countriesData_Renamed As List(Of CountryStatisticInfo)

        Private selectedCountry_Renamed As CountryStatisticInfo

        Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

        Public Shared ReadOnly Property Instance() As DashboardViewModel
            Get
                If instance_Renamed Is Nothing Then
                    instance_Renamed = New DashboardViewModel()
                End If
                Return instance_Renamed
            End Get
        End Property

        Public ReadOnly Property CountriesData() As List(Of CountryStatisticInfo)
            Get
                Return countriesData_Renamed
            End Get
        End Property
        Public Property SelectedCountry() As CountryStatisticInfo
            Get
                Return selectedCountry_Renamed
            End Get
            Set(ByVal value As CountryStatisticInfo)
                If selectedCountry_Renamed IsNot value Then
                    selectedCountry_Renamed = value
                    OnPropertyChanged("SelectedCountry")
                End If
            End Set
        End Property

        Public Sub PopulateData(ByVal filepath As String)
            countriesData_Renamed.AddRange(CountriesInfoDataReader.Load(filepath))
            selectedCountry_Renamed = countriesData_Renamed(0)
        End Sub

        Private Sub New()
            countriesData_Renamed = New List(Of CountryStatisticInfo)()
        End Sub

        Private Sub OnPropertyChanged(ByVal propertyName As String)
            Dim propertyChangedEventHendler As PropertyChangedEventHandler = PropertyChangedEvent
            If propertyChangedEventHendler IsNot Nothing Then
                propertyChangedEventHendler(Me, New PropertyChangedEventArgs(propertyName))
            End If
        End Sub
    End Class

    Friend Class CountriesInfoDataReader
        Private Shared Function LoadStatistic(ByVal populationDynamic As XElement) As List(Of PopulationStatisticByYear)
            Dim statistic As New List(Of PopulationStatisticByYear)()
            For Each populationDynamicItem As XElement In populationDynamic.Elements("PopulationStatisticByYear")
                Dim year As Integer = Integer.Parse(populationDynamicItem.Element("Year").Value)
                Dim population As Long = Long.Parse(populationDynamicItem.Element("Population").Value)
                Dim urbanPercent As Double = Double.Parse(populationDynamicItem.Element("UrbanPercent").Value, CultureInfo.InvariantCulture)
                Dim popDynamicItem As New PopulationStatisticByYear(year, CDbl(population) / 1000000.0, urbanPercent)
                statistic.Add(popDynamicItem)
            Next populationDynamicItem
            Return statistic
        End Function

        Public Shared Function Load(ByVal path As String) As List(Of CountryStatisticInfo)
            Dim doc As XDocument = XDocument.Load(path)
            Dim data As New List(Of CountryStatisticInfo)()
            For Each countryInfo As XElement In doc.Root.Elements("CountryInfo")
                Dim name As String = countryInfo.Element("Name").Value
                Dim areaSqKm As Double = UInteger.Parse(countryInfo.Element("AreaSqrKilometers").Value)
                Dim statistic As List(Of PopulationStatisticByYear) = LoadStatistic(countryInfo.Element("Statistic"))
                Dim countryInfoInstance As New CountryStatisticInfo(name, areaSqKm / 1000000, statistic)
                data.Add(countryInfoInstance)
            Next countryInfo
            Return data
        End Function
    End Class
End Namespace
vb
Imports System.Collections.Generic

Namespace MVVM_Selection.Model
    Public Class CountryStatisticInfo

        Private ReadOnly name_Renamed As String

        Private ReadOnly area_Renamed As Double
        Private ReadOnly statistics As List(Of PopulationStatisticByYear)

        Public ReadOnly Property Name() As String
            Get
                Return name_Renamed
            End Get
        End Property
        ' Measured in millions of square kilometers.
        Public ReadOnly Property Area() As Double
            Get
                Return area_Renamed
            End Get
        End Property
        Public ReadOnly Property PopulationDynamics() As List(Of PopulationStatisticByYear)
            Get
                Return statistics
            End Get
        End Property
        Public Sub New(ByVal name As String, ByVal area As Double, ByVal statistics As List(Of PopulationStatisticByYear))
            Me.name_Renamed = name
            Me.area_Renamed = area
            Me.statistics = statistics
        End Sub
    End Class

    Public Class PopulationStatisticByYear

        Private year_Renamed As Integer
        Private populationMillionsOfPeople As Double

        Private urbanPercent_Renamed As Double

        Public ReadOnly Property Year() As Integer
            Get
                Return year_Renamed
            End Get
        End Property
        ' Measured in Millions of people.
        Public ReadOnly Property Population() As Double
            Get
                Return populationMillionsOfPeople
            End Get
        End Property
        Public ReadOnly Property UrbanPercent() As Double
            Get
                Return urbanPercent_Renamed
            End Get
        End Property
        Public ReadOnly Property RuralPercent() As Double
            Get
                Return 100 - urbanPercent_Renamed
            End Get
        End Property

        Public Sub New(ByVal year As Integer, ByVal populationMillionsOfPeople As Double, ByVal urbanPercent As Double)
            Me.year_Renamed = year
            Me.populationMillionsOfPeople = populationMillionsOfPeople
            Me.urbanPercent_Renamed = urbanPercent
        End Sub
    End Class
End Namespace
vb
Imports MVVM_Selection.ViewModel
Imports System.Windows

Namespace MVVM_Selection
    Partial Public Class MainWindow
        Inherits Window

        Public Sub New()
            InitializeComponent()
            Dim viewModel = DashboardViewModel.Instance
            viewModel.PopulateData("..\..\Data\Top10LargestCountriesInfo.xml")
            DataContext = viewModel
        End Sub
    End Class
End Namespace
csharp
using MVVM_Selection.Model;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Xml.Linq;

namespace MVVM_Selection.ViewModel {
    public class DashboardViewModel : INotifyPropertyChanged {
        static DashboardViewModel instance;
        readonly List<CountryStatisticInfo> countriesData;
        CountryStatisticInfo selectedCountry;

        public event PropertyChangedEventHandler PropertyChanged;

        public static DashboardViewModel Instance {
            get {
                if (instance == null) instance = new DashboardViewModel();
                return instance;
            }
        }

        public List<CountryStatisticInfo> CountriesData {
            get { return countriesData; }
        }
        public CountryStatisticInfo SelectedCountry {
            get { return selectedCountry; }
            set {
                if (selectedCountry != value) {
                    selectedCountry = value;
                    OnPropertyChanged("SelectedCountry");
                }
            }
        }

        public void PopulateData(string filepath) {
            countriesData.AddRange(CountriesInfoDataReader.Load(filepath));
            selectedCountry = countriesData[0];
        }

        DashboardViewModel() {
            countriesData = new List<CountryStatisticInfo>();
        }

        void OnPropertyChanged(string propertyName) {
            PropertyChangedEventHandler propertyChangedEventHendler = PropertyChanged;
            if (propertyChangedEventHendler != null)
                propertyChangedEventHendler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    class CountriesInfoDataReader {
        static List<PopulationStatisticByYear> LoadStatistic(XElement populationDynamic) {
            List<PopulationStatisticByYear> statistic = new List<PopulationStatisticByYear>();
            foreach (XElement populationDynamicItem in populationDynamic.Elements("PopulationStatisticByYear")) {
                int year = int.Parse(populationDynamicItem.Element("Year").Value);
                long population = long.Parse(populationDynamicItem.Element("Population").Value);
                double urbanPercent = double.Parse(populationDynamicItem.Element("UrbanPercent").Value, CultureInfo.InvariantCulture);
                PopulationStatisticByYear popDynamicItem = new PopulationStatisticByYear(year, (double)population / 1000000.0, urbanPercent);
                statistic.Add(popDynamicItem);
            }
            return statistic;
        }

        public static List<CountryStatisticInfo> Load(string path) {
            XDocument doc = XDocument.Load(path);
            List<CountryStatisticInfo> data = new List<CountryStatisticInfo>();
            foreach (XElement countryInfo in doc.Root.Elements("CountryInfo")) {
                string name = countryInfo.Element("Name").Value;
                double areaSqKm = uint.Parse(countryInfo.Element("AreaSqrKilometers").Value);
                List<PopulationStatisticByYear> statistic = LoadStatistic(countryInfo.Element("Statistic"));
                CountryStatisticInfo countryInfoInstance = new CountryStatisticInfo(name, areaSqKm / 1000000, statistic);
                data.Add(countryInfoInstance);
            }
            return data;
        }
    }
}
csharp
using System.Collections.Generic;

namespace MVVM_Selection.Model {
    public class CountryStatisticInfo {
        readonly string name;
        readonly double area;
        readonly List<PopulationStatisticByYear> statistics;

        public string Name
        {
            get { return name; }
        }
        // Measured in millions of square kilometers.
        public double Area
        {
            get { return area; }
        }
        public List<PopulationStatisticByYear> PopulationDynamics
        {
            get { return statistics; }
        }
        public CountryStatisticInfo(string name, double area, List<PopulationStatisticByYear> statistics) {
            this.name = name;
            this.area = area;
            this.statistics = statistics;
        }
    }

    public class PopulationStatisticByYear {
        int year;
        double populationMillionsOfPeople;
        double urbanPercent;

        public int Year
        {
            get { return year; }
        }
        // Measured in Millions of people.
        public double Population
        {
            get { return populationMillionsOfPeople; }
        }
        public double UrbanPercent
        {
            get { return urbanPercent; }
        }
        public double RuralPercent
        {
            get { return 100 - urbanPercent; }
        }

        public PopulationStatisticByYear(int year, double populationMillionsOfPeople, double urbanPercent) {
            this.year = year;
            this.populationMillionsOfPeople = populationMillionsOfPeople;
            this.urbanPercent = urbanPercent;
        }
    }
}
csharp
using MVVM_Selection.ViewModel;
using System.Windows;

namespace MVVM_Selection {
    public partial class MainWindow : Window {

        public MainWindow() {
            InitializeComponent();
            var viewModel = DashboardViewModel.Instance;
            viewModel.PopulateData(@"..\..\Data\Top10LargestCountriesInfo.xml");
            DataContext = viewModel;
        }
    }
}