前一篇文章裡面講到了實作一個直方圖控件所要注意的問題,既然是一個控件,那麼需要先将給使用者調用的API調用出來。如果讀者有使用Office Excel的經驗的話,就會發現,制作一個直方圖,實際上隻需要顯示直方圖的資料就可以了,如下圖所示:
上圖,再分解一下,可以看到每一個Series是一個系列的資料(比如一個數組);而每一個Category可以看成是用來識别一個資料的辨別(例如數組的下标);當然最後剩下的就是資料啦。是以直方圖控件給使用者的定義的使用方法應該是:
Xaml代碼:
<Window x:Class="CodeLibrary.Test.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CodeLibrary.Charts"
Loaded="Window_Loaded" Title="Window1" Height="600" Width="800">
<local:Histogram x:Name="TestHistogram"
Width="8000"/>
</Window>
C#代碼:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
double[] test = new double[256];
double[] test2 = new double[256];
Random random = new Random(1000);
for (int i = 0; i < test.Length; ++i)
{
test[i] = random.Next();
test2[i] = random.Next();
}
TestHistogram.HistogramData = test;
TestHistogram.AddHistogramData(test2, "Series 2");
}
這樣一來,控件的最基本的API已經定義完畢,至于直方圖其它的屬性,可以等到整個直方圖完善了以後再慢慢添加進去。對比WPF的控件實作方式,使用UserControl會比從已有的一個控件繼承下來更友善一些,因為編輯UserControl的Xaml會相對直覺一些。在寫代碼之前,先講一下思路,為什麼可以使用ItemsControl(ListBox是從ItemsControl繼承下來的)來繪制一個直方圖,先看看一個最普通的ItemsControl的代碼:
預設情況,ListBox是以垂直排列的方式來排列每一個清單項的,而ListBox中的ItemsPanel屬性允許你替換掉預設的排列清單項的面闆,ListBox使用的預設面闆是VirtualizingStackPanel,在資料綁定的情況下,VirtualizingStackPanel這個面闆隻會從綁定的資料裡面建立在電腦螢幕中顯示的清單項,這樣最大程度優化了界面的性能—好東西。預設情況下,VirtualizingStackPanel是垂直排列放在裡面的控件的—這就是為什麼ListBox是垂直排列清單項的原因。
那麼現在嘗試一下将ListBox預設的排列行為改成橫向排列,請看下圖:
上面的代碼,将VirtualizingStackPanel的布局方式從垂直排版改到水準排版,ListBox的清單項的布局方式也改變了。有了這個基礎以後,我們來看如何實作直方圖,其實我們可以把直方圖看成一個大“竹簡”,“竹簡”裡面的每一塊顯示直方圖 裡面的一個矩形和X軸上面的刻度,Y軸我們先不考慮,是以直方圖可以以類似下面的角度來看:
這樣一來,借助重載ItemsControl的ItemTemplate和ItemsPanel屬性,比如下面的代碼可以得到一個最簡單的直方圖的式樣了:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib"
xmlns:collection="clr-namespace:System.Collections;assembly=mscorlib">
<Page.Resources>
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="data">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="HorizontalAlignment" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Page.Resources>
<ListBox ItemsSource="{Binding Source={StaticResource data}}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="50">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Fill="Gray" Height="100" />
<Label HorizontalAlignment="Center" Content="{Binding}" Padding="0"Margin="0" Grid.Row="1" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Page>
下圖就是最終得到的效果:
好了,接下來的問題就是如何把前面Xaml裡面寫死的資料用實際程式中變化的資料代替,未完待續……
本文轉自 donjuan 部落格園部落格,原文連結: http://www.cnblogs.com/killmyday/archive/2009/07/22/1528758.html,如需轉載請自行聯系原作者