MVVM模式下动态绑定X/Y值到图表遇轴适配错误求助
问题:动态绑定LineSeries时出现"No suitable axis is available"错误
我的UI通过磁贴展示多个数据点,点击磁贴会打开新窗口绘制该字段最近60条数据的时间趋势图。采用MVVM架构,尝试把X轴(SampleTime)和Y值动态绑定到DotNetProjects.DataVisualization.Toolkit的LineSeries时,抛出错误:
System.InvalidOperationException: 'No suitable axis is available for plotting the dependent value.'
ViewModel代码
public partial class MainViewChartVM : ObservableObject { private const int N_RECORDS = 60; private DataProperty _currentChartItem; public enum DataProperty { AmbientTemp, RelativeHumidity, BarometricPressure, WindSpeed, WindDirection, } public MainViewChartVM(DataProperty currentChartItem) { _currentChartItem = currentChartItem; InitializeChart(); } [ObservableProperty] private string _chartTitle; [ObservableProperty] private string _chartUnits; [ObservableProperty] private ObservableCollection<Sample_Data> _currentDataSet; [ObservableProperty] private string _independentValuePath; [ObservableProperty] private string _dependentValuePath; private void InitializeChart() { // Update button options // Update chart CurrentDataSet = new ObservableCollection<Sample_Data>(DataLogger.Instance.ReadLastNSamples(N_RECORDS)); IndependentValuePath = nameof(Sample_Data.SampleTime); switch (_currentChartItem) { case DataProperty.AmbientTemp: ChartTitle = nameof(Sample_Data.AmbientTemp); DependentValuePath = nameof(Sample_Data.AmbientTemp); break; case DataProperty.RelativeHumidity: break; case DataProperty.BarometricPressure: break; case DataProperty.WindSpeed: break; case DataProperty.WindDirection: break; default: break; } } }
View代码
<Window x:Class="Monitor.Views.Misc.MainViewChart" 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:Monitor.Views.Misc" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:properties="clr-namespace:Monitor.Properties" xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=DotNetProjects.DataVisualization.Toolkit" mc:Ignorable="d" Title="MainViewChart" Height="600" Width="1024" WindowStyle="None" WindowStartupLocation="CenterScreen" ResizeMode="NoResize" WindowState="Maximized"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="80"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <DockPanel Background="{StaticResource Blue4}" HorizontalAlignment="Stretch"> <Label Content="" DockPanel.Dock="Left" Style="{StaticResource LabelScreenTitle}"/> <Button Focusable="False" Foreground="White" Background="Transparent" BorderBrush="{x:Null}" Width="80" HorizontalAlignment="Right" DockPanel.Dock="Right" Style="{StaticResource NoHover}" Click="Button_Click"> <iconPacks:Material Kind="Close" Width="50" Height="50"/> </Button> </DockPanel> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition Width="4*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <charting:Chart x:Name="MyChart" Background="#f8f8f8ff" BorderBrush="Transparent" Grid.Column="0"> <charting:Chart.Series> <charting:LineSeries Title="Your Series Title" ItemsSource="{Binding CurrentDataSet}" IndependentValueBinding="{Binding IndependentValuePath}" DependentValueBinding="{Binding DependentValuePath}"> <charting:LineSeries.DataPointStyle> <Style TargetType="charting:LineDataPoint"> <Setter Property="Background" Value="Blue"/> <Setter Property="Width" Value="0"/> <Setter Property="Height" Value="0"/> </Style> </charting:LineSeries.DataPointStyle> </charting:LineSeries> </charting:Chart.Series> <charting:Chart.Axes> <charting:LinearAxis Orientation="X" Title="{x:Static properties:Resources.Display_Time}"/> <charting:LinearAxis Orientation="Y" Title="{Binding ChartUnits}"/> </charting:Chart.Axes> <charting:Chart.LegendStyle> <Style TargetType="Control"> <Setter Property="Width" Value="0"/> <Setter Property="Height" Value="0"/> </Style> </charting:Chart.LegendStyle> </charting:Chart> <Grid Grid.Column="1"> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="8*"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <Button Grid.Row="0" Command="{Binding PreviousDataSetCommand}" Margin="1"> <iconPacks:Material Kind="ChevronUp" Width="25" Height="25"/> </Button> <UniformGrid Grid.Row="1" Rows="6" Margin="1"> <Button Content="test" Margin="1" Style="{StaticResource NormalButton}"/> <Button Content="test" Margin="1" Style="{StaticResource NormalButton}"/> <Button Content="test" Margin="1" Style="{StaticResource NormalButton}"/> <Button Content="test" Margin="1" Style="{StaticResource NormalButton}"/> <Button Content="test" Margin="1" Style="{StaticResource NormalButton}"/> <Button Content="test" Margin="1" Style="{StaticResource NormalButton}"/> </UniformGrid> <Button Grid.Row="2" Command="{Binding PreviousDataSetCommand}" Margin="1"> <iconPacks:Material Kind="ChevronDown" Width="25" Height="25"/> </Button> </Grid> </Grid> </Grid> </Window>
解决方案
1. 修正X轴类型为DateTimeAxis
X轴绑定的SampleTime是时间类型,当前使用的LinearAxis无法适配时间数据,需替换为DateTimeAxis:
<charting:Chart.Axes> <charting:DateTimeAxis Orientation="X" Title="{x:Static properties:Resources.Display_Time}"/> <charting:LinearAxis Orientation="Y" Title="{Binding ChartUnits}"/> </charting:Chart.Axes>
2. 修正LineSeries的绑定属性
对于动态指定属性名称的场景,应使用IndependentValuePath和DependentValuePath而非Binding语法:
<charting:LineSeries Title="Your Series Title" ItemsSource="{Binding CurrentDataSet}" IndependentValuePath="{Binding IndependentValuePath}" DependentValuePath="{Binding DependentValuePath}">
3. 补全ViewModel的switch分支
当前仅实现了AmbientTemp分支,其他数据项未设置DependentValuePath会导致绑定为空引发错误,补全所有分支并设置对应单位:
switch (_currentChartItem) { case DataProperty.AmbientTemp: ChartTitle = nameof(Sample_Data.AmbientTemp); DependentValuePath = nameof(Sample_Data.AmbientTemp); ChartUnits = "°C"; break; case DataProperty.RelativeHumidity: ChartTitle = nameof(Sample_Data.RelativeHumidity); DependentValuePath = nameof(Sample_Data.RelativeHumidity); ChartUnits = "%"; break; case DataProperty.BarometricPressure: ChartTitle = nameof(Sample_Data.BarometricPressure); DependentValuePath = nameof(Sample_Data.BarometricPressure); ChartUnits = "hPa"; break; case DataProperty.WindSpeed: ChartTitle = nameof(Sample_Data.WindSpeed); DependentValuePath = nameof(Sample_Data.WindSpeed); ChartUnits = "m/s"; break; case DataProperty.WindDirection: ChartTitle = nameof(Sample_Data.WindDirection); DependentValuePath = nameof(Sample_Data.WindDirection); ChartUnits = "°"; break; default: break; }
4. 验证数据有效性
确保DataLogger.Instance.ReadLastNSamples(N_RECORDS)返回的数据集非空,且每条数据的SampleTime和对应Y值均为有效类型(时间类型/数值类型),避免空值或类型不匹配导致轴无法识别。
内容的提问来源于stack exchange,提问作者Baddack
相关产品推荐
相关产品推荐

