如何实现LiveCharts多图表LabelVisual随光标同步更新?
多图表同步更新LabelVisual文本的解决方案
问题场景
我有多个图表,每个图表都包含一个LabelVisual,要求当光标沿X轴移动时,所有图表的该标签文本均需更新,而非仅更新光标所在的图表。目前仅能实现光标所在图表的标签文本更新,现寻求解决方案。
相关代码
MainWindow.axaml
<Window> <Design.DataContext> <vm:MainWindowViewModel2/> </Design.DataContext> <Window.DataContext> <vm:MainWindowViewModel2 /> </Window.DataContext> <ScrollViewer AllowAutoHide="True"> <ItemsControl x:Name="ItemsGraphs" PointerMoved="ItemsControl_PointerMoved" ItemsSource="{Binding ItemsGraphs}" > <ItemsControl.DataTemplates> <views:ItemsTemplateSelector> <DataTemplate x:Key="{x:Type vm:ViewModelLineSmoothness}"> <views:LineSmoothness/> </DataTemplate> <DataTemplate x:Key="{x:Type vm:ViewModelDiscreteSignal}"> <views:DiscreteSignal/> </DataTemplate> </views:ItemsTemplateSelector> </ItemsControl.DataTemplates> </ItemsControl> </ScrollViewer> </Window>
LineSmoothness.axaml
<UserControl> <lvca:CartesianChart Name="ChartLine" Series="{Binding Series}" Sections="{Binding Sections}" YAxes="{Binding YAxes}" XAxes="{Binding XAxes}" Background="White" Height="200" Margin="5" LegendPosition="Right" LegendTextPaint="{Binding LegendTextPaint}" LegendTextSize="12" TooltipTextSize="10" VisualElements="{Binding VisualElements}" PointerPressedCommand="{Binding PointerDownCommand}" PointerMoveCommand="{Binding PointerMoveCommand}" TooltipPosition ="Auto" ZoomMode="ZoomY"> <lvca:CartesianChart.DrawMarginFrame> <lvc:DrawMarginFrame> <lvc:DrawMarginFrame.Stroke> <lvcp:SolidColorPaint Color="#808080" StrokeThickness="1" /> </lvc:DrawMarginFrame.Stroke> </lvc:DrawMarginFrame> </lvca:CartesianChart.DrawMarginFrame> </lvca:CartesianChart> </UserControl>
ViewModelLineSmoothness.cs
... public LiveChartsCore.SkiaSharpView.VisualElements.LabelVisual labelMarker; public ObservableCollection<ChartElement<SkiaSharpDrawingContext>> VisualElements => visuals; public ViewModelLineSmoothness() { labelMarker = new LiveChartsCore.SkiaSharpView.VisualElements.LabelVisual { HorizontalAlignment = Align.Start, TextSize = 15, X = 100, Y = 100, Paint = new SolidColorPaint(SKColors.Red) { ZIndex = 11, SKTypeface = SKTypeface.FromFamilyName("Courier New") }, BackgroundColor = new LvcColor(55, 71, 79).WithOpacity(10), Padding = new Padding(5), LocationUnit = MeasureUnit.Pixels, }; visuals.Add(labelMarker); } [RelayCommand] public void PointerMoveCommand(PointerCommandArgs args) { labelMarker.Text = $"{args.PointerPosition.X:f2}"; labelMarker.X = args.PointerPosition.X; labelMarker.Y = args.PointerPosition.Y; labelMarker.Invalidate((Chart<SkiaSharpDrawingContext>)args.Chart.CoreChart); } ...
解决方案
核心思路是将光标X轴位置作为共享状态托管在主ViewModel中,所有子图表ViewModel监听该状态变化,实现同步更新。
步骤1:主ViewModel添加共享光标位置属性
修改MainWindowViewModel2,维护可观察的光标X轴位置,并在值变更时通知所有子ViewModel更新标签:
using System.ComponentModel; using System.Runtime.CompilerServices; using System.Collections.ObjectModel; public class MainWindowViewModel2 : INotifyPropertyChanged { private double _currentCursorX; public double CurrentCursorX { get => _currentCursorX; set { if (_currentCursorX != value) { _currentCursorX = value; OnPropertyChanged(); // 遍历所有子ViewModel,触发标签更新 foreach (var item in ItemsGraphs) { if (item is ViewModelLineSmoothness lineVm) lineVm.UpdateLabelMarker(value); else if (item is ViewModelDiscreteSignal discreteVm) discreteVm.UpdateLabelMarker(value); } } } } public ObservableCollection<object> ItemsGraphs { get; set; } = new(); public event PropertyChangedEventHandler? PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string? propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
步骤2:子ViewModel添加标签更新方法
修改ViewModelLineSmoothness,移除原有的PointerMoveCommand,新增接收共享X轴位置并更新标签的方法:
public class ViewModelLineSmoothness { public LiveChartsCore.SkiaSharpView.VisualElements.LabelVisual labelMarker; public ObservableCollection<ChartElement<SkiaSharpDrawingContext>> VisualElements => visuals; private readonly ObservableCollection<ChartElement<SkiaSharpDrawingContext>> visuals = new(); public ViewModelLineSmoothness() { labelMarker = new LiveChartsCore.SkiaSharpView.VisualElements.LabelVisual { HorizontalAlignment = Align.Start, TextSize = 15, X = 100, Y = 100, Paint = new SolidColorPaint(SKColors.Red) { ZIndex = 11, SKTypeface = SKTypeface.FromFamilyName("Courier New") }, BackgroundColor = new LvcColor(55, 71, 79).WithOpacity(10), Padding = new Padding(5), LocationUnit = MeasureUnit.Pixels, }; visuals.Add(labelMarker); } // 接收主ViewModel传递的X轴值,更新标签 public void UpdateLabelMarker(double cursorX) { labelMarker.Text = $"{cursorX:f2}"; // 如果需要同步标签的X坐标,可根据图表坐标逻辑转换后赋值 // labelMarker.X = ...; labelMarker.Invalidate(); } }
步骤3:主窗口统一处理光标移动事件
在MainWindow.axaml.cs中实现ItemsControl_PointerMoved,将屏幕坐标转换为图表X轴值,更新主ViewModel的共享状态:
using Avalonia.Input; using LiveChartsCore.SkiaSharpView.Avalonia; public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void ItemsControl_PointerMoved(object? sender, PointerEventArgs e) { if (DataContext is not MainWindowViewModel2 mainVm) return; var itemsControl = sender as ItemsControl; if (itemsControl?.Items.Count == 0) return; // 获取任意一个图表实例用于坐标转换 var firstContainer = itemsControl.ItemContainerGenerator.ContainerFromIndex(0) as ContentPresenter; if (firstContainer?.ContentTemplate.LoadContent() is not LineSmoothness lineView) return; var chart = lineView.ChartLine; if (chart == null) return; // 转换屏幕坐标为图表X轴数据值 var pointerPos = e.GetPosition(chart); var dataPoint = chart.CoreChart.PointerPositionToDataPoint(pointerPos); if (dataPoint == null) return; mainVm.CurrentCursorX = dataPoint.X; } }
步骤4:移除子图表的光标移动命令绑定
修改LineSmoothness.axaml,删除PointerMoveCommand的绑定:
<lvca:CartesianChart Name="ChartLine" Series="{Binding Series}" Sections="{Binding Sections}" YAxes="{Binding YAxes}" XAxes="{Binding XAxes}" Background="White" Height="200" Margin="5" LegendPosition="Right" LegendTextPaint="{Binding LegendTextPaint}" LegendTextSize="12" TooltipTextSize="10" VisualElements="{Binding VisualElements}" PointerPressedCommand="{Binding PointerDownCommand}" TooltipPosition ="Auto" ZoomMode="ZoomY"> <!-- 其他内容不变 --> </lvca:CartesianChart>
内容的提问来源于stack exchange,提问作者chemo
相关产品推荐
相关产品推荐

