[LiveCharts2] 資料對應--使用 Mapper

接下來要談到的是使用 Series<TModel, TVisual, TLabel, TDrawingContext>.Mapping 屬性來做資料對應。

前言

LiveCharts 裡有兩種資料對應方式,其中一種就是使用 Mapper,過程很簡單,設定 Series<TModel, TVisual, TLabel, TDrawingContext>.Mapping Property 即可。

Mapping 屬性的型別是一個 Func<TModel, int, Coordinate> ,這表示傳入兩個參數 (1) 自訂的資料型別 (2) 資料在集合的索引,然後回傳 Coordinate。

準備工作(1) 圖表的基本 View Model

這次我將圖表直接繫結的 View Model 獨立設計,後面 MainViewModel 會引入這個型別。

 public class ChartCommonViewModel : NotifyPropertyBase
 {
     private ObservableCollection<ISeries> _series;
     private ObservableCollection<Axis> _xAxes;
     private ObservableCollection<Axis> _yAxes;
     public ObservableCollection<ISeries> Series
     {
         get => _series;
         set => SetProperty(ref _series, value);
     }

     public ObservableCollection<Axis> XAxes
     {
         get => _xAxes;
         set => SetProperty(ref _xAxes, value);
     }

     public ObservableCollection<Axis> YAxes
     {
         get => _yAxes;
         set => SetProperty(ref _yAxes, value);
     }
     private SolidColorPaint _toolTipTextPaint;
     public SolidColorPaint ToolTipTextPaint
     {
         get => _toolTipTextPaint;
         set => SetProperty(ref _toolTipTextPaint, value);
     }
     public ChartCommonViewModel()
     {
         Series = new ObservableCollection<ISeries>();
         XAxes = new ObservableCollection<Axis>();
         YAxes = new ObservableCollection<Axis>();
     }
 }
準備工作 (2) 單筆資料的 View Model
 public class PersonViewModel : NotifyPropertyBase
 {
     private string _name;
     public string Name
     {
         get => _name;
         set => SetProperty(ref _name, value);
     }

     private int _score;
     public int Score
     {
         get => _score;
         set => SetProperty(ref _score, value);
     }
 }
完成 MainViewModel
 public class MainViewModel : NotifyPropertyBase
 {
     private ObservableCollection<PersonViewModel> _people;
     public ObservableCollection<PersonViewModel> People
     {
         get => _people;
         set => SetProperty(ref _people, value);
     }

     public MainViewModel()
     {
         InitialData();           
         Chart = new ChartCommonViewModel();
         AddSeries();
         AddXAxes();
         AddYAxes();
         CreateTextPaint();
     }
     private void InitialData()
     {
         People = new ObservableCollection<PersonViewModel>()
         {
             new PersonViewModel { Name = "魯夫" , Score = 98},
             new PersonViewModel { Name = "索隆" , Score = 79},
             new PersonViewModel { Name = "香吉士" , Score = 58},
             new PersonViewModel { Name = "娜美" , Score = 82},
             new PersonViewModel { Name = "羅賓" , Score = 100},
             new PersonViewModel { Name = "喬巴" , Score = 43},
         };
     }
     private void CreateTextPaint()
     {
         Chart.ToolTipTextPaint = new SolidColorPaint
         {
             Color = SKColors.Black,
             SKTypeface = SKFontManager.Default.MatchFamily("新細明體"),
         };
     }

     private void AddSeries()
     {
         Chart.Series.Add(
               new ColumnSeries<PersonViewModel>
               {
                   Mapping = (person, index) => new Coordinate(index, person.Score),
                   Values = People,
               });
     }

     private void AddXAxes()
     {
         Chart.XAxes.Add(
             new Axis
             {
                 Labels = new ObservableCollection<string>(People.Select(x => x.Name)),
                 LabelsPaint = new SolidColorPaint
                 {
                     Color = SKColors.Black,
                     SKTypeface = SKFontManager.Default.MatchFamily("新細明體"),
                 },
             });
     }

     private void AddYAxes()
     {
         Chart.YAxes.Add(
              new Axis
              {
                  Labeler = value => $"{value} 分",
                  LabelsPaint = new SolidColorPaint
                  {
                      Color = SKColors.Black,
                      SKTypeface = SKFontManager.Default.MatchFamily("新細明體"),
                  },
              });
     }         

     private ChartCommonViewModel _chart;
     public ChartCommonViewModel Chart
     {
         get => _chart;
         set => SetProperty(ref _chart, value);
     }
 }

主要關注的程式碼在 AddSeries() 方法內部:

 private void AddSeries()
 {
     Chart.Series.Add(
           new ColumnSeries<PersonModel>
           {
               Mapping = (person, index) => new Coordinate(index, person.Score),
               Values = People,
           });
 }

加入一段長條圖的資料,設定他的X軸資料對應 index,Y軸資料對應 PersnViewModel.Score 屬性。

Y 軸的設定相當簡單,因為我們要顯示的就是分數,所以直接用 Labeler 屬性 (這是個 Func<double,string>),把每一筆 PersnViewModel.Score 透過他轉成字串顯示:

 private void AddYAxes()
 {
     Chart.YAxes.Add(
          new Axis
          {
              Labeler = value => $"{value} 分",
              LabelsPaint = new SolidColorPaint
              {
                  Color = SKColors.Black,
                  SKTypeface = SKFontManager.Default.MatchFamily("新細明體"),
              },
          });
 }

X 軸就麻煩了些,因為 Mapping 取得的 X 軸的值是 index,但我們並沒有想要顯示 0,1,2,3,4 ….,而是要顯示 PersonViewModel.Name,所以要做點手腳:

 private void AddXAxes()
 {
     Chart.XAxes.Add(
         new Axis
         {
             Labels = new ObservableCollection<string>(People.Select(x => x.Name)),
             LabelsPaint = new SolidColorPaint
             {
                 Color = SKColors.Black,
                 SKTypeface = SKFontManager.Default.MatchFamily("新細明體"),
             },
         });
 }

畫面很簡單就長這樣:

<Window x:Class="LiveChartsV2Sample003.MainWindow"
        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:LiveChartsV2Sample003"
        xmlns:lvc="clr-namespace:LiveChartsCore.SkiaSharpView.WPF;assembly=LiveChartsCore.SkiaSharpView.WPF"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.DataContext >
        <local:MainViewModel />
    </Window.DataContext>
    <Grid>
        <lvc:CartesianChart Series="{Binding Chart.Series}"
                            XAxes="{Binding Chart.XAxes}"
                            YAxes="{Binding Chart.YAxes}"
                            TooltipTextPaint="{Binding Chart.ToolTipTextPaint}">
        </lvc:CartesianChart>
    </Grid>
</Window>

順帶一提,TooltipTextPaint 屬性可以用來設定 ToolTip 的顯示字型,因為用中文,所以需要設定此屬性讓 ToolTip 顯示正確的文字。

本篇文章的範例在此