天天看點

使用ListBox控件來實作直方圖控件(二)

前一篇文章裡面講到了實作一個直方圖控件所要注意的問題,既然是一個控件,那麼需要先将給使用者調用的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,如需轉載請自行聯系原作者

繼續閱讀