如何将自定义工具提示集成到 LiveCharts 中的折线图中

How to integrate custom tooltips into line chart in LiveCharts

参考资料

  1. 制作折线图:https://lvcharts.net/App/examples/v1/Wpf/Line
  2. 生成工具提示:https://lvcharts.net/App/examples/v1/Wpf/Tooltips%20and%20Legends

我想做什么

我想制作一个自定义工具提示,就像参考 2 中的条形示例一样,但在参考 1 中

我做了什么

我复制粘贴了参考 2 中的工具提示,对其进行了更改以适应不同的变量

出了什么问题

工具提示最多显示框颜色,不显示变量值。

灰色方框应包含文字,但只显示灰色方框。

我的代码

MainWindow 和 Tooltip(称为 HITooltop)的 xaml 和 xaml.cs 数据

MainWindow.xaml

<UserControl x:Class="NeoSpace.MainWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:NeoSpace"
             xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <lvc:CartesianChart Series="{Binding SeriesCollection}" LegendLocation="Right" >
            <lvc:CartesianChart.AxisY>
                <lvc:Axis Title="Sales" LabelFormatter="{Binding YFormatter}"></lvc:Axis>
            </lvc:CartesianChart.AxisY>
            <lvc:CartesianChart.AxisX>
                <lvc:Axis Title="Month" Labels="{Binding Labels}"></lvc:Axis>
            </lvc:CartesianChart.AxisX>
            <lvc:CartesianChart.DataTooltip>
                <local:HITooltip/>
            </lvc:CartesianChart.DataTooltip>
        </lvc:CartesianChart>
    </Grid>
</UserControl>

主窗口。xaml.cs

using System;
using System.Windows.Controls;
using LiveCharts;
using LiveCharts.Wpf;

namespace NeoSpace
{
    public partial class MainWindow : UserControl
    {
        public MainWindow()
        {
            InitializeComponent();
            GraphicOutput HI01 = new GraphicOutput("Device01", "01-02-03-40-50-12", "Idle", 
                new ChartValues<double> { 3, 6, 9, 12, 15 }, new ChartValues<double> { 3, 6, 9, 12, 15 });
            GraphicOutput HI02 = new GraphicOutput("Device02", "01-02-03-40-50-12", "Idle");
            GraphicOutput HI03 = new GraphicOutput(
                new ChartValues<double> { 5, 10, 15, 20, 25 }, new ChartValues<double> { 5, 10, 15, 20, 25 });
            SeriesCollection = new SeriesCollection
            {
                new LineSeries
                {
                    Title = HI01.Device,
                    Values = HI01.Thoroughput
                },
                new LineSeries
                {
                    Title = HI02.Device,
                    Values = HI02.Thoroughput,
                    PointGeometry = null
                },
                new LineSeries
                {
                    Title = HI03.Device,
                    Values = HI03.Thoroughput,
                    PointGeometry = DefaultGeometries.Square,
                    PointGeometrySize = 15
                }
            };

            Labels = new[] { "Time 01", "Time 02", "Time 03", "Time 04", "Time 05" };
            YFormatter = value => value.ToString();
            DataContext = this;
        }
        public SeriesCollection SeriesCollection { get; set; }
        public string[] Labels { get; set; }
        public Func<double, string> YFormatter { get; set; }
    }
}

HITooltip.xaml

<UserControl x:Class="NeoSpace.HITooltip"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:wpf="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
             xmlns:local="clr-namespace:NeoSpace"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300"
             d:DataContext="{d:DesignInstance local:HITooltip}"
             Background="#E4555555" Padding="20 10" BorderThickness="2" BorderBrush="Orange">
    <ItemsControl ItemsSource="{Binding Data.Points}" Grid.IsSharedSizeScope="True">
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type wpf:DataPointViewModel}">
                <Grid Margin="2">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto" SharedSizeGroup="Device"/>
                        <ColumnDefinition Width="Auto" SharedSizeGroup="BDAddress"/>
                        <ColumnDefinition Width="Auto" SharedSizeGroup="State"/>
                        <ColumnDefinition Width="Auto" SharedSizeGroup="Thoroughput"/>
                    </Grid.ColumnDefinitions>
                    <Rectangle Grid.Column="0" Stroke="{Binding Series.Stroke}" Fill="{Binding Series.Fill}"
                               Height="15" Width="15"></Rectangle>
                    <TextBlock Grid.Column="1" Text="{Binding ChartPoint.Instance.(local:GraphicOutput.Device)}" 
                               Margin="5 0 0 0" VerticalAlignment="Center" Foreground="White"/>
                    <TextBlock Grid.Column="2" Text="{Binding ChartPoint.Instance.(local:GraphicOutput.BDAddress)}" 
                               Margin="5 0 0 0" VerticalAlignment="Center" Foreground="White"/>
                    <TextBlock Grid.Column="3" Text="{Binding ChartPoint.Instance.(local:GraphicOutput.State)}" 
                               Margin="5 0 0 0" VerticalAlignment="Center" Foreground="White"/>
                    <TextBlock Grid.Column="3" Text="{Binding ChartPoint.Instance.(local:GraphicOutput.Thoroughput)}" 
                               Margin="5 0 0 0" VerticalAlignment="Center" Foreground="White"/>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

HITooltip.xaml.cs

using System.ComponentModel;
using LiveCharts;
using LiveCharts.Wpf;

namespace NeoSpace
{
    public partial class HITooltip : IChartTooltip
    {
        private TooltipData _data;

        public HITooltip()
        {
            InitializeComponent();
            DataContext = this;
        }

        public TooltipData Data
        {
            get { return _data; }
            set
            {
                _data = value;
                OnPropertyChanged("TooltipData");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public TooltipSelectionMode? SelectionMode { get; set; }

        protected virtual void OnPropertyChanged(string propertyName = null)
        {
            if (PropertyChanged != null)
            { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); }
        }
    }
}

要绘制的 class GraphicOutput 和工具提示上显示的值

using LiveCharts;

namespace NeoSpace
{
    public class GraphicOutput
    {
        public string Device { get; set; }
        public string BDAddress { get; set; }
        public string State { get; set; }
        public ChartValues<double> FrameSize { get; set; }
        public ChartValues<double> Thoroughput { get; set; }

        public GraphicOutput(string a, string b, string c, ChartValues<double> d1, ChartValues<double> d2)
        {
            Device = a;
            BDAddress = b;
            State = c;
            FrameSize = d1;
            Thoroughput = d2;
        }

        public GraphicOutput(string a, string b, string c)
        {
            Device = a;
            BDAddress = b;
            State = c;
            FrameSize = new ChartValues<double> { 1, 2, 3, 4, 5 };
            Thoroughput = new ChartValues<double> { 1, 2, 3, 4, 5 };
        }

        public GraphicOutput(ChartValues<double> d1, ChartValues<double> d2)
        {
            Device = "A Device";
            BDAddress = "11:22:33:44:55:66";
            State = "Too Idle";
            FrameSize = d1;
            Thoroughput = d2;
        }
    }
}

HITooltip class 中,属性 名称应为 Data 而不是 TooltipData

public TooltipData Data
{
    get { return _data; }
    set
    {
        _data = value;
        OnPropertyChanged("Data");
    }
}

我是怎么得到答案的

  • Tooltip.cs
using System.Windows.Controls;
using System.ComponentModel;
using LiveCharts;
using LiveCharts.Wpf;

namespace BraGraphHybridWithCustomTooltips
{
    /// <summary>
    /// Interaction logic for HybridTooltip.xaml
    /// </summary>
    public partial class HybridTooltip : IChartTooltip
    {
        private TooltipData _data;
        public HybridTooltip()
        {
            InitializeComponent();
            DataContext = this;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public TooltipData Data
        {
            get { return _data; }
            set
            {
                _data = value;
                OnPropertyChanged("Data");
            }
        }

        public TooltipSelectionMode? SelectionMode { get; set; }

        protected virtual void OnPropertyChanged(string propertyName = null)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
  • Tooltip.xaml
<UserControl x:Class="BraGraphHybridWithCustomTooltips.HybridTooltip"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:wpf="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
             xmlns:local="clr-namespace:BraGraphHybridWithCustomTooltips"
             xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             d:DataContext="{d:DesignInstance local:HybridTooltip}">
    <ItemsControl ItemsSource="{Binding Data.Points}" Grid.IsSharedSizeScope="True">
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type wpf:DataPointViewModel}">
                <Grid Margin="2">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="*" SharedSizeGroup="State"/>
                        <ColumnDefinition Width="*" SharedSizeGroup="Framesize"/>
                    </Grid.ColumnDefinitions>
                    <Rectangle Grid.Column="0" Stroke="{Binding Series.Stroke}" Fill="{Binding Series.Fill}"
                               Height="15" Width="15" VerticalAlignment="Center" Margin="5 0 5 0"/>
                    <WrapPanel Grid.Column="1" >
                        <TextBlock Text="State:" Margin="5 0 0 0"/>
                        <TextBlock Text="{Binding ChartPoint.Instance.(local:InputClass.State)}" 
                                Margin="5 0 0 0" VerticalAlignment="Center"/>
                    </WrapPanel>
                    <WrapPanel Grid.Column="3" >
                        <TextBlock Text="Framesize:" Margin="5 0 0 0"/>
                        <TextBlock Text="{Binding ChartPoint.Instance.(local:InputClass.Framesize)}" 
                                Margin="5 0 0 0" VerticalAlignment="Center"/>
                    </WrapPanel>
                </Grid>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</UserControl>

将它应用到 Main Window 上

<Window x:Class="BraGraphHybridWithCustomTooltips.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:BraGraphHybridWithCustomTooltips"
        xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:HybridTooltip/>
    </Grid>
</Window>

瞧瞧(就 LiveCharts 而言)