使用OxyPlot在WPF中创建图表

目录(?)[+]

  1. Using Nuget
  2. 包括OxyPlot在你的应用程序的最简单方法是使用NuGet包管理器在Visual Studio 运行 Visual Studio并开始创建一个新的WPF项目选择一个名称和位置并点击OK
  3. Create the ViewModel
  4. Adding the graph to the page
  5. Binding the model to the view
  6. Set up the Graph PlotModel
  7. The data
  8. Add the data to the PlotModel
  9. 在视图模型中我们将创建一个新的方法其中的loaddata我们会得到的数据并添加一些代码来绘制所有点在图形上
  10. Updating the graph real-time
  11. Update the view model
  12. Update from the view
  13. Avoid to many updates
  14. 渲染事件是理想的以避免异常但你会看到每秒许多更新以保持图形的可读性我们可以解决这个添加一个秒表在后面的代码只触发更新当最后更新至少一秒钟前
  15. Source code
 
对于我们的项目之一,我们必须从外部源检索数据,并将它们存储在数据库中。一个来自客户机的请求,是看在图形中检索到的数据。此外,他希望看到一个实时更新该图中检索数据的每一秒。 
经过一番搜索,我发现OxyPlot库。这个库可以在WPF,Silverlight中,Windows窗体,甚至在Windows Store应用程序中使用。在现在正在研究一个alpha版本为单声道。 
虽然包已经下载超过10万次不会有这么多的博客文章查找有关实施库。虽然包已经下载超过10万次不会有这么多的博客文章查找有关实施库。

Using Nuget

包括OxyPlot在你的应用程序的最简单方法是使用NuGet包管理器在Visual Studio。 运行 Visual Studio,并开始创建一个新的WPF项目。选择一个名称和位置,并点击“OK”。

image

创建项目后,打开管理器控制台,在提示符下键入以下命令并打(每一个命令之后),请输入: 
安装封装Oxyplot.Core 
安装封装Oxyplot.Wpf

image

当然你也可以使用软件包管理器用户界面右击引用,然后选择管理NuGet软件包和他们的方式。

Create the ViewModel

我们将使用MVVM模式(部分)呈现在屏幕上的图表。第一步是创建视图模型为我们MainWindow.xaml。用鼠标右键单击该项目,并添加一个文件夹的ViewModels。用鼠标右键单击该文件夹并添加一个类MainWindowModel.cs。

image

要使用MVVM模式,我们需要使公共类和继承INotifyPropertyChanged接口。 
继承接口后,我们必须实现PropertyChangedEventHandler事件,如下图所示。
1234567891011121314151617
using System.ComponentModel;
using OxyPlotDemo.Annotations;
 
namespace OxyPlotDemo.ViewModels
{
public class MainWindowModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
 
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
view rawgistfile1.cs hosted with ❤ by GitHub

现在,我们可以补充一点,我们会绑定到XAML页面的一些公共属性。首先创建一个PlotModel那是OxyPlot库的一部分。在构造函数中,我们将启动PlotModel参数。设定器将调用,将通知该视图中有物体上的变化,可能有要呈现的OnPropertyChanged方法。

123456789101112131415161718192021222324252627282930
using System.ComponentModel;
using OxyPlot;
using OxyPlotDemo.Annotations;
 
namespace OxyPlotDemo.ViewModels
{
public class MainWindowModel: INotifyPropertyChanged
{
private PlotModel plotModel;
public PlotModel PlotModel
{
get { return plotModel; }
set { plotModel = value; OnPropertyChanged("PlotModel"); }
}
 
public MainWindowModel()
{
PlotModel = new PlotModel();
}
 
public event PropertyChangedEventHandler PropertyChanged;
 
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
view rawgistfile1.cs hosted with ❤ by GitHub

Adding the graph to the page

现在,我们可以将图形添加到MainWindow.xaml页面。之前,我们可以添加图形,我们将需要添加的命名空间OxyPlot库(4号线)。我们将在PlotModel参数绑定到我们在视图模型创建的PlotModel。

12345678910
<Window x:Class="OxyPlotDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:oxy="http://oxyplot.codeplex.com"
Title="MainWindow" Height="350" Width="525">
<Grid>
<oxy:Plot x:Name="Plot1" Title="A Graph" Model="{Binding PlotModel}" Margin="10" Grid.Row="1">
</oxy:Plot>
</Grid>
</Window>
view rawgistfile1.xml hosted with ❤ by GitHub

Binding the model to the view

最后一部分,我们的设置是视图模型绑定到视图。因为我们不使用任何的MVVM框架,我们将不得不手动绑定模型在MainWindow.xaml页面背后的代码。 


加入我们的视图模型的私有财产,并启动该属性在构造函数中。点的DataContext这个属性,我们就大功告成了。
123456789101112131415161718192021
using System.Windows;
 
namespace OxyPlotDemo
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ViewModels.MainWindowModel viewModel;
 
public MainWindow()
{
viewModel = new ViewModels.MainWindowModel();
DataContext = viewModel
 
 
InitializeComponent();
}
}
}
view rawgistfile1.cs hosted with ❤ by GitHub

如果我们按F5键运行该应用程序,我们会看到一个空窗口打开。我们有一些数据的过程中添加到PlotModel图将呈现前。

Set up the Graph – PlotModel

回到我们的视图模型来建立我们的视图模型。第一次启动将增加轴的图,从而OxyPlot知道在哪里可以绘制点。 
在我们的视图模型类中创建一个新的方法SetUpModel。在这里我们将定义图表的图例(位置,边界,陛下,...),并添加2轴。则DateTimeAxis我们的X轴(我们要在一条线上的时间绘制点)和ValuaAxis我们的Y轴。
1234567891011121314
private void SetUpModel()
{
PlotModel.LegendTitle = "Legend";
PlotModel.LegendOrientation = LegendOrientation.Horizontal;
PlotModel.LegendPlacement = LegendPlacement.Outside;
PlotModel.LegendPosition = LegendPosition.TopRight;
PlotModel.LegendBackground = OxyColor.FromAColor(200, OxyColors.White);
PlotModel.LegendBorder = OxyColors.Black;
 
var dateAxis = new DateTimeAxis(AxisPosition.Bottom, "Date", "dd/MM/yy HH:mm") { MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, IntervalLength = 80 };
PlotModel.Axes.Add(dateAxis);
var valueAxis = new LinearAxis(AxisPosition.Left, 0) { MajorGridlineStyle = LineStyle.Solid, MinorGridlineStyle = LineStyle.Dot, Title = "Value" };
PlotModel.Axes.Add(valueAxis);
}
view rawgistfile1.cs hosted with ❤ by GitHub
该设置为图形的传说是自我解释。在第10行,你会看到创建的DateTimeAxis的。我们选择的轴的位置,给它一个名称(日期)和字符串格式样式如何日期有显示。下一步,我们将添加一些参数来显示主要和次要网格线和间隔大小。创建后,我们将添加轴到PlotModel。 
该ValueAxis类似于发起的,只是我们没有定位轴左侧,并告诉轴心国开始在0值。 
如果我们添加一个调用此方法,我们认为模型的构造,并再次按F5键,我们会看到窗口打开,其中包含一个空图。

image

The data

现在,我们有我们的图形,并准备了一些图线添加到PlotModel。在这篇文章中,我们将添加四个不同的线路,这将是情节。 
为了避免复杂性我添加了一个类Data.cs其中的数据是硬编码的。在现实生活中应用程序,您将实现一个数据库调用或一个服务调用或Web API请求,... 
我将接收到的数据将是我创建了一个新的简单类的列表<T>:测量。这个类有3个公共参数:一个DetectorId(长),数据(int)和日期时间(DateTime的)。我已经添加了4种不同的探测器,每个有10个测量值的1到30之间的随机值。

Add the data to the PlotModel

在视图模型中,我们将创建一个新的方法,其中的loaddata我们会得到的数据,并添加一些代码来绘制所有点在图形上。

1234567891011121314151617181920212223
private void LoadData()
{
List<Measurement> measurements = Data.GetData();
 
var dataPerDetector = measurements.GroupBy(m => m.DetectorId).ToList();
 
foreach (var data in dataPerDetector)
{
var lineSerie = new LineSeries
{
StrokeThickness = 2,
MarkerSize = 3,
MarkerStroke = colors[data.Key],
MarkerType = markerTypes[data.Key],
CanTrackerInterpolatePoints = false,
Title = string.Format("Detector {0}",data.Key),
Smooth = false,
};
 
data.ToList().ForEach(d=>lineSerie.Points.Add(new DataPoint(DateTimeAxis.ToDouble(d.DateTime),d.Value)));
PlotModel.Series.Add(lineSerie);
}
}
view rawgistfile1.cs hosted with ❤ by GitHub
获取数据后,我将使用LINQ GROUPBY表达式创建一个IEnumerable的与关键的DetectorId和值和DateTime的集合作为值。 (第5行) 
这将允许我们遍历的结果,然后添加每一个探测器LineSerie。在LineSerie的设置,我们将设置喜欢的颜色和线条粗细和标题的一些性质。 (9号线至18)。 
之后我们建立了LineSerie我们可以添加指向LineSerie。我们利用DateTimeAxis将内置类函数来将日期转换为一张双人床和增加值(第20行)。 
之后,我们添加了指向LineSerie我们仍然不得不在LineSerie添加到PlotModel。 (第21行)。 
就是这样。按F5键,你会看到那些图形会被渲染,并且每探测器的线会出现绘制1到30之间的随机值。

image

Updating the graph real-time

对于我们的客户端的第二个问题,我们必须添加实时更新。对于这个演示中,我将添加一个新的测量到图形的每一秒。该OxyPlot库将确保我们的图表将每一起我们将添加一个新的测量时间移动。 
我添加了一个静态方法在Data.cs类,将返回一个随机值,将沿发送的DateTime参数后一秒钟。在视图模型我已经创建了一个私有参数的DateTime参数(lasUpdate),将持有我们最后更新图表的时刻。

Update the view model

我们将添加一个新的方法到视图模型的UpdateModel。这一次,我们将它公开,因此它可以从视图中被调用,如图中的下一个篇章。 
在的UpdateModel方法,我们会从出Data.cs类获取数据,并执行相同的分组行动,在方法的loaddata。 
这将使我们能够获取每个探测器的数据。获取正确的LineSerie后就像我们在方法的loaddata做我们可以添加点。
12345678910111213141516
public void UpdateModel()
{
List<Measurement> measurements = Data.GetUpdateData(lastUpdate);
var dataPerDetector = measurements.GroupBy(m => m.DetectorId).OrderBy(m => m.Key).ToList();
 
foreach (var data in dataPerDetector)
{
var lineSerie = PlotModel.Series[data.Key] as LineSeries;
if (lineSerie != null)
{
data.ToList()
.ForEach(d => lineSerie.Points.Add(new DataPoint(DateTimeAxis.ToDouble(d.DateTime), d.Value)));
}
}
lastUpdate = DateTime.Now;
}
view rawgistfile1.cs hosted with ❤ by GitHub

Update from the view

我们不希望该模型的更新开始之前,前一个是完全呈现,以避免我们正在修改,同时渲染图形列表的例外。为此,我们利用一个CompositionTarget.Rendering事件。此事件会在每次视图渲染完成时触发。 
在的MainWindow.xaml.cs类的构造函数中,我们将附加一个事件处理程序的渲染事件。 
在事件处理程序中,我们会从视图模型调用update方法。在这个调用之后,我们将要告诉PlotModel,有一个更新,他必须刷新图形(第14行)。 (这是OxyPlot偏离了MVVM模式)。
123456789101112131415
public MainWindow()
{
viewModel = new ViewModels.MainWindowModel();
DataContext = viewModel;
 
CompositionTarget.Rendering += CompositionTargetRendering;
 
InitializeComponent();
}
 
private void CompositionTargetRendering(object sender, EventArgs e)
{
viewModel.UpdateModel();
Plot1.RefreshPlot(true);
}
view rawgistfile1.cs hosted with ❤ by GitHub

Avoid to many updates

渲染事件是理想的,以避免异常,但你会看到每秒许多更新,以保持图形的可读性。我们可以解决这个添加一个秒表在后面的代码,只触发更新当最后更新至少一秒钟前。

123456789101112131415161718192021222324
        public MainWindow()
{
viewModel = new ViewModels.MainWindowModel();
DataContext = viewModel;
 
CompositionTarget.Rendering += CompositionTargetRendering;
stopwatch.Start();
 
InitializeComponent();
}
 
private long frameCounter;
private System.Diagnostics.Stopwatch stopwatch = new Stopwatch();
private long lastUpdateMilliSeconds;
 
private void CompositionTargetRendering(object sender, EventArgs e)
{
if (stopwatch.ElapsedMilliseconds > lastUpdateMilliSeconds + 5000)
{
viewModel.UpdateModel();
Plot1.RefreshPlot(true);
lastUpdateMilliSeconds = stopwatch.ElapsedMilliseconds;
}
}
view rawgistfile1.cs hosted with ❤ by GitHub

加入秒表后,我们会看到每一个(这个演示5秒),一个新的点添加到图形。

image

Source code

正如你所看到的,与OxyPlot你不需要写很多的代码来创建实时更新图表。 
OxyPlot有更多的选项和图形样式,他们提供了一个演示页面,各种图形在Silverlight中呈现。您可以复制源代码与键盘组合键Ctrl+ Alt键+ C。如果您要复制的属性使用CTRL + ALT + R。 
这篇文章的源代码可以为你找到Github上。欢迎到餐桌,下载,...
原文地址:https://www.cnblogs.com/lvdongjie/p/5659322.html