WPF 图表工具包:如何在添加实时数据时设置固定的 X 轴范围
WPF Charting Toolkit: How to set a fixed X-axis range while adding real time data
我正在做一个基于 WPF 图表工具包的应用程序实时数据图表。我通过串行端口获取数据。
设置图表代码如下:
<chartingToolkit:Chart Margin="10,10,10,0" ClipToBounds="True" x:Name="chart1" Title="Chart Title">
<chartingToolkit:LineSeries IndependentValueBinding="{Binding Value1}" DependentValueBinding="{Binding Value2}" ItemsSource="{Binding}" Background="Transparent" Cursor="No">
<chartingToolkit:LineSeries.DataPointStyle>
<Style TargetType="{x:Type chartingToolkit:LineDataPoint}">
<Setter Property="Height" Value="0"/>
<Setter Property="Width" Value="0" />
<Setter Property="Background" Value="Green"/>
</Style>
</chartingToolkit:LineSeries.DataPointStyle>
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
效果很好,但我仍然需要设置 X 轴的最大值和最小值。
X 值 (Value1) 是接收样本的数量,Y 轴值 (Value2) 显然是接收样本的具体值。
我的问题是关于X轴范围。
目前,我得到的最小值为 0,最大值为串行端口在当前时刻接收到的最大样本数。
但我想设置一个我想看到的永久 X 轴范围。
例如我想在 X 轴上看到 500 个样本的范围。
表示当样本数超过500时,max为最大样本数,min为max-500.
主要难点是在WPF中如何用实时数据设置??
谁能帮帮我吗??
更新问题
我正在根据@jstreet 的建议更新我的问题。
我有这个方法 运行 在 MainWindow class 的单独线程中,如下所示。
public partial class MainWindow : Window
{
public SerialPort serialPort1 = new SerialPort();
public string rx_str = "";
public string rx_str_copy;
public int a;
public double x, y;
ObservableCollection<ChartData> chartData;
ChartData objChartData;
Thread myThread;
public MainWindow()
{
InitializeComponent();
string[] port = SerialPort.GetPortNames();
foreach (string a in port)
{
comboPorts.Items.Add(a);
}
Array.Sort(port);
comboPorts.Text = port[0];
objChartData = new ChartData();
chartData.Add(objChartData);
chart1.DataContext = chartData;
myThread = new Thread(new ThreadStart(Run));
}
public void Run()
{
while (true)
{
serialPort1.Write("a");
rx_str = serialPort1.ReadTo("b");
rx_str_copy = rx_str;
x = a;
y = Double.Parse(rx_str_copy, CultureInfo.InvariantCulture);
a++;
Dispatcher.Invoke(new Action(delegate
{
chartData.Add(new ChartData() { Value1 = x,
Value2= y });
}));
}
}
此运行() 方法负责接收数据并将其添加到图表。
在另一个 class 中,我对即将到来的数据和设置属性 Valeu1 和 Value2 有反应:
public class ChartData : INotifyPropertyChanged
{
double _Value1;
double _Value2;
public double Value1
{
get
{
return _Value1;
}
set
{
_Value1 = value;
OnPropertyChanged("Value1");
}
}
public double Value2
{
get
{
return _Value2;
}
set
{
_Value2 = value;
OnPropertyChanged("Value2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
}
}
}
如何使@jstreet 的解决方案适应我的后台代码示例?
在您的视图模型中创建一个 MinValue
依赖项 属性 并将其绑定到您的轴 Minimum
属性。看看:
XAML:
<Window
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:WpfApp31"
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
x:Class="WpfApp31.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MyViewModel/>
</Window.DataContext>
<Grid>
<chartingToolkit:Chart Title="My Sample">
<chartingToolkit:Chart.Axes>
<chartingToolkit:LinearAxis Minimum="{Binding MinValue}" Orientation="X"></chartingToolkit:LinearAxis>
</chartingToolkit:Chart.Axes>
<chartingToolkit:LineSeries IndependentValueBinding="{Binding Value1}"
DependentValueBinding="{Binding Value2}"
ItemsSource="{Binding Data}">
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
</Grid>
</Window>
查看模型:
public class MyViewModel : DependencyObject
{
public int MinValue
{
get { return (int)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
// Using a DependencyProperty as the backing store for MinValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(int), typeof(MyViewModel), new PropertyMetadata(default(int)));
public ObservableCollection<MyDataModel> Data { get; set; }
private Timer serialPort;
private Random y;
private int x;
private int range;
public MyViewModel()
{
range = 10;
Data = new ObservableCollection<MyDataModel>();
y = new Random(DateTime.Now.Millisecond);
serialPort = new Timer(DataReceived, null, 500, 500);
}
private void DataReceived(object state)
{
Application.Current.Dispatcher.Invoke(() => {
Data.Add(new MyDataModel { Value1 = x, Value2 = y.Next(10, 90) });
MinValue = x < range ? 0 : x - range;
x++;
});
}
}
编辑: 作为记录,我可能不会像下面那样编写这段代码。我在这里这样做只是为了让你可以继续前进。
XAML:
<Window
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:WpfApp1"
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
x:Class="WpfApp1.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<chartingToolkit:Chart Grid.Row="0" Margin="10,10,10,0" ClipToBounds="True" x:Name="chart1" Title="Chart Title">
<chartingToolkit:Chart.Axes>
<chartingToolkit:LinearAxis Minimum="{Binding MinValue}" Orientation="X"></chartingToolkit:LinearAxis>
</chartingToolkit:Chart.Axes>
<chartingToolkit:LineSeries IndependentValueBinding="{Binding Value1}" DependentValueBinding="{Binding Value2}" ItemsSource="{Binding chartData}" Background="Transparent" Cursor="No">
<chartingToolkit:LineSeries.DataPointStyle>
<Style TargetType="{x:Type chartingToolkit:LineDataPoint}">
<Setter Property="Height" Value="0"/>
<Setter Property="Width" Value="0" />
<Setter Property="Background" Value="Green"/>
</Style>
</chartingToolkit:LineSeries.DataPointStyle>
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
<Button Grid.Row="1" x:Name="btn1" Click="btn1_Click">START</Button>
</Grid>
CS:
public partial class MainWindow : Window
{
public double MinValue
{
get { return (double)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
// Using a DependencyProperty as the backing store for MinValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(double), typeof(MainWindow), new PropertyMetadata(default(double)));
//public SerialPort serialPort1 = new SerialPort();
//public string rx_str = "";
//public string rx_str_copy;
//public int a;
public double x, y;
public ObservableCollection<ChartData> chartData { get; set; }
ChartData objChartData;
Thread myThread;
Random r;
int range = 50;
public MainWindow()
{
InitializeComponent();
r = new Random();
DataContext = this;
/*
string[] port = SerialPort.GetPortNames();
foreach (string a in port)
{
comboPorts.Items.Add(a);
}
Array.Sort(port);
comboPorts.Text = port[0];
*/
objChartData = new ChartData();
chartData = new ObservableCollection<ChartData>();
chartData.Add(objChartData);
//chart1.DataContext = chartData;
myThread = new Thread(new ThreadStart(Run));
}
private void btn1_Click(object sender, RoutedEventArgs e)
{
myThread.Start();
}
public void Run()
{
while (true)
{
//serialPort1.Write("a");
//rx_str = serialPort1.ReadTo("b");
//rx_str_copy = rx_str;
//x = a;
//y = Double.Parse(rx_str_copy, CultureInfo.InvariantCulture);
//a++;
Dispatcher.Invoke(new Action(delegate
{
chartData.Add(new ChartData()
{
Value1 = x,
Value2 = r.NextDouble(),
//Value2 = y
});
MinValue = x < range ? 0 : x - range;
x++;
}));
Thread.Sleep(50);
}
}
}
我正在做一个基于 WPF 图表工具包的应用程序实时数据图表。我通过串行端口获取数据。 设置图表代码如下:
<chartingToolkit:Chart Margin="10,10,10,0" ClipToBounds="True" x:Name="chart1" Title="Chart Title">
<chartingToolkit:LineSeries IndependentValueBinding="{Binding Value1}" DependentValueBinding="{Binding Value2}" ItemsSource="{Binding}" Background="Transparent" Cursor="No">
<chartingToolkit:LineSeries.DataPointStyle>
<Style TargetType="{x:Type chartingToolkit:LineDataPoint}">
<Setter Property="Height" Value="0"/>
<Setter Property="Width" Value="0" />
<Setter Property="Background" Value="Green"/>
</Style>
</chartingToolkit:LineSeries.DataPointStyle>
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
效果很好,但我仍然需要设置 X 轴的最大值和最小值。 X 值 (Value1) 是接收样本的数量,Y 轴值 (Value2) 显然是接收样本的具体值。
我的问题是关于X轴范围。
目前,我得到的最小值为 0,最大值为串行端口在当前时刻接收到的最大样本数。
但我想设置一个我想看到的永久 X 轴范围。
例如我想在 X 轴上看到 500 个样本的范围。
表示当样本数超过500时,max为最大样本数,min为max-500.
主要难点是在WPF中如何用实时数据设置??
谁能帮帮我吗??
更新问题
我正在根据@jstreet 的建议更新我的问题。
我有这个方法 运行 在 MainWindow class 的单独线程中,如下所示。
public partial class MainWindow : Window
{
public SerialPort serialPort1 = new SerialPort();
public string rx_str = "";
public string rx_str_copy;
public int a;
public double x, y;
ObservableCollection<ChartData> chartData;
ChartData objChartData;
Thread myThread;
public MainWindow()
{
InitializeComponent();
string[] port = SerialPort.GetPortNames();
foreach (string a in port)
{
comboPorts.Items.Add(a);
}
Array.Sort(port);
comboPorts.Text = port[0];
objChartData = new ChartData();
chartData.Add(objChartData);
chart1.DataContext = chartData;
myThread = new Thread(new ThreadStart(Run));
}
public void Run()
{
while (true)
{
serialPort1.Write("a");
rx_str = serialPort1.ReadTo("b");
rx_str_copy = rx_str;
x = a;
y = Double.Parse(rx_str_copy, CultureInfo.InvariantCulture);
a++;
Dispatcher.Invoke(new Action(delegate
{
chartData.Add(new ChartData() { Value1 = x,
Value2= y });
}));
}
}
此运行() 方法负责接收数据并将其添加到图表。
在另一个 class 中,我对即将到来的数据和设置属性 Valeu1 和 Value2 有反应:
public class ChartData : INotifyPropertyChanged
{
double _Value1;
double _Value2;
public double Value1
{
get
{
return _Value1;
}
set
{
_Value1 = value;
OnPropertyChanged("Value1");
}
}
public double Value2
{
get
{
return _Value2;
}
set
{
_Value2 = value;
OnPropertyChanged("Value2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
}
}
}
如何使@jstreet 的解决方案适应我的后台代码示例?
在您的视图模型中创建一个 MinValue
依赖项 属性 并将其绑定到您的轴 Minimum
属性。看看:
XAML:
<Window
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:WpfApp31"
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
x:Class="WpfApp31.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MyViewModel/>
</Window.DataContext>
<Grid>
<chartingToolkit:Chart Title="My Sample">
<chartingToolkit:Chart.Axes>
<chartingToolkit:LinearAxis Minimum="{Binding MinValue}" Orientation="X"></chartingToolkit:LinearAxis>
</chartingToolkit:Chart.Axes>
<chartingToolkit:LineSeries IndependentValueBinding="{Binding Value1}"
DependentValueBinding="{Binding Value2}"
ItemsSource="{Binding Data}">
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
</Grid>
</Window>
查看模型:
public class MyViewModel : DependencyObject
{
public int MinValue
{
get { return (int)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
// Using a DependencyProperty as the backing store for MinValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(int), typeof(MyViewModel), new PropertyMetadata(default(int)));
public ObservableCollection<MyDataModel> Data { get; set; }
private Timer serialPort;
private Random y;
private int x;
private int range;
public MyViewModel()
{
range = 10;
Data = new ObservableCollection<MyDataModel>();
y = new Random(DateTime.Now.Millisecond);
serialPort = new Timer(DataReceived, null, 500, 500);
}
private void DataReceived(object state)
{
Application.Current.Dispatcher.Invoke(() => {
Data.Add(new MyDataModel { Value1 = x, Value2 = y.Next(10, 90) });
MinValue = x < range ? 0 : x - range;
x++;
});
}
}
编辑: 作为记录,我可能不会像下面那样编写这段代码。我在这里这样做只是为了让你可以继续前进。
XAML:
<Window
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:WpfApp1"
xmlns:chartingToolkit="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
x:Class="WpfApp1.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<chartingToolkit:Chart Grid.Row="0" Margin="10,10,10,0" ClipToBounds="True" x:Name="chart1" Title="Chart Title">
<chartingToolkit:Chart.Axes>
<chartingToolkit:LinearAxis Minimum="{Binding MinValue}" Orientation="X"></chartingToolkit:LinearAxis>
</chartingToolkit:Chart.Axes>
<chartingToolkit:LineSeries IndependentValueBinding="{Binding Value1}" DependentValueBinding="{Binding Value2}" ItemsSource="{Binding chartData}" Background="Transparent" Cursor="No">
<chartingToolkit:LineSeries.DataPointStyle>
<Style TargetType="{x:Type chartingToolkit:LineDataPoint}">
<Setter Property="Height" Value="0"/>
<Setter Property="Width" Value="0" />
<Setter Property="Background" Value="Green"/>
</Style>
</chartingToolkit:LineSeries.DataPointStyle>
</chartingToolkit:LineSeries>
</chartingToolkit:Chart>
<Button Grid.Row="1" x:Name="btn1" Click="btn1_Click">START</Button>
</Grid>
CS:
public partial class MainWindow : Window
{
public double MinValue
{
get { return (double)GetValue(MinValueProperty); }
set { SetValue(MinValueProperty, value); }
}
// Using a DependencyProperty as the backing store for MinValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MinValueProperty =
DependencyProperty.Register("MinValue", typeof(double), typeof(MainWindow), new PropertyMetadata(default(double)));
//public SerialPort serialPort1 = new SerialPort();
//public string rx_str = "";
//public string rx_str_copy;
//public int a;
public double x, y;
public ObservableCollection<ChartData> chartData { get; set; }
ChartData objChartData;
Thread myThread;
Random r;
int range = 50;
public MainWindow()
{
InitializeComponent();
r = new Random();
DataContext = this;
/*
string[] port = SerialPort.GetPortNames();
foreach (string a in port)
{
comboPorts.Items.Add(a);
}
Array.Sort(port);
comboPorts.Text = port[0];
*/
objChartData = new ChartData();
chartData = new ObservableCollection<ChartData>();
chartData.Add(objChartData);
//chart1.DataContext = chartData;
myThread = new Thread(new ThreadStart(Run));
}
private void btn1_Click(object sender, RoutedEventArgs e)
{
myThread.Start();
}
public void Run()
{
while (true)
{
//serialPort1.Write("a");
//rx_str = serialPort1.ReadTo("b");
//rx_str_copy = rx_str;
//x = a;
//y = Double.Parse(rx_str_copy, CultureInfo.InvariantCulture);
//a++;
Dispatcher.Invoke(new Action(delegate
{
chartData.Add(new ChartData()
{
Value1 = x,
Value2 = r.NextDouble(),
//Value2 = y
});
MinValue = x < range ? 0 : x - range;
x++;
}));
Thread.Sleep(50);
}
}
}