使用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 raw gistfile1.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 raw gistfile1.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 raw gistfile1.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 raw gistfile1.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 raw gistfile1.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 raw gistfile1.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 raw gistfile1.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 raw gistfile1.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 raw gistfile1.cs hosted with ❤ by  GitHub

加入秒表后,我們會看到每一個(這個演示5秒),一個新的點添加到圖形。

image

Source code

 

正如你所看到的,與OxyPlot你不需要寫很多的代碼來創建實時更新圖表。 
OxyPlot有更多的選項和圖形樣式,他們提供了一個演示頁面,各種圖形在Silverlight中呈現。您可以復制源代碼與鍵盤組合鍵Ctrl+ Alt鍵+ C。如果您要復制的屬性使用CTRL + ALT + R。 
這篇文章的源代碼可以為你找到Github上。歡迎到餐桌,下載,...


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM