使用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會比從已有的一個控件繼承下來更方便一些,因爲編輯UserControlXaml會相對直觀一些。在寫代碼之前,先講一下思路,爲什麼可以使用ItemsControl(ListBox是從ItemsControl繼承下來的)來繪製一個直方圖,先看看一個最普通的ItemsControl的代碼:

 

默認情況,ListBox是以垂直排列的方式來排列每一個列表項的,而ListBox中的ItemsPanel屬性允許你替換掉默認的排列列表項的面板,ListBox使用的默認面板是VirtualizingStackPanel,在數據綁定的情況下,VirtualizingStackPanel這個面板只會從綁定的數據裏面創建在電腦屏幕中顯示的列表項,這樣最大程度優化了界面的性能好東西。默認情況下,VirtualizingStackPanel是垂直排列放在裏面的控件的這就是爲什麼ListBox是垂直排列列表項的原因。

那麼現在嘗試一下將ListBox默認的排列行爲改成橫向排列,請看下圖:

 

上面的代碼,將VirtualizingStackPanel的佈局方式從垂直排版改到水平排版,ListBox的列表項的佈局方式也改變了。有了這個基礎以後,我們來看如何實現直方圖,其實我們可以把直方圖看成一個大“竹簡”,“竹簡”裏面的每一塊顯示直方圖 裏面的一個矩形和X軸上面的刻度,Y軸我們先不考慮,因此直方圖可以以類似下面的角度來看:

 

這樣一來,藉助重載ItemsControlItemTemplateItemsPanel屬性,比如下面的代碼可以得到一個最簡單的直方圖的式樣了:

<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裏面硬編碼的數據用實際程序中變化的數據代替,未完待續……

發佈了73 篇原創文章 · 獲贊 2 · 訪問量 39萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章