将对象中的 X 和 Y 值绑定到 MVVM 中的图表

问题描述 投票:0回答:1
我有一个 UI 显示,它在屏幕上以图块形式显示多个数据点。如果用户单击某个图块,我想打开一个新窗口,并根据时间绘制该字段的最后 60 个数据点的图表。但是,我正在尝试使用 MVVM 方法,但在将 X 和 Y 值动态绑定到图表时遇到了问题。如有任何帮助,我们将不胜感激。

我的视图模型:

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; } } }
我的看法:

<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>
当我尝试绘制参数图表时出现以下错误:

System.InvalidOperationException:“没有合适的轴可用于绘制从属值。”

c# wpf mvvm
1个回答
0
投票
问题在于

IndependentValueBinding

DependentValueBinding
 不是路径,而是绑定到实际数据属性。处理您想要做的事情的一个好方法可能是为该 
Sample_Data
 对象创建一个视图模型。然后你可以通过构造函数中的
DataProperty
参数传入你想要显示的数据。

这是一个示例。

示例_DataViewModel

public class Sample_DataViewModel { public Sample_DataViewModel(Sample_Data dataModel, MainViewChartVM.DataProperty dataProperty) { DataModel = dataModel; _currentChartItem = dataProperty; } public double IndependentValue => DataModel.SampleTime; public double DependentValue { get { switch (_currentChartItem) { case MainViewChartVM.DataProperty.AmbientTemp: return DataModel.AmbientTemp; case MainViewChartVM.DataProperty.RelativeHumidity: return DataModel.RelativeHumidity; // ToDo: build out the other options, returning zero for now case MainViewChartVM.DataProperty.BarometricPressure: case MainViewChartVM.DataProperty.WindSpeed: case MainViewChartVM.DataProperty.WindDirection: default: return 0; } } } public Sample_Data DataModel { get; } public MainViewChartVM.DataProperty _currentChartItem { get; } }
MainViewChartVM

// ToDo: these are not needed //[ObservableProperty] //private string _independentValuePath; //[ObservableProperty] //private double _dependentValue; private void InitializeChart() { // this is the sample data I used for testing var mockData = new Sample_Data[]{ new Sample_Data(0,0,4), new Sample_Data(1,1,3), new Sample_Data(1.5,2,2), new Sample_Data(1.6,3,3), new Sample_Data(2,4,1), }; // Update chart CurrentDataSet = new ObservableCollection<Sample_DataViewModel>( mockData.Select(x => new Sample_DataViewModel(x, _currentChartItem))); }
XAML 图表绑定:

<charting:LineSeries Title="Your Series Title" ItemsSource="{Binding CurrentDataSet}" IndependentValueBinding="{Binding IndependentValue}" DependentValueBinding="{Binding DependentValue}">
结果

您可以在这里查看生成的代码文件:

https://github.com/EvanGeer/StackOverflowAnswers/blob/master/StackOverflowAnswers.Revit/StackOverflowAnswers.App/ChartingExample.xaml.cs

环境温度模拟数据:

相对湿度模拟数据:

© www.soinside.com 2019 - 2024. All rights reserved.