使用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里面硬编码的数据用实际程序中变化的数据代替,未完待续……

原文地址:https://www.cnblogs.com/killmyday/p/1528758.html