当前位置:首页 > 开发教程 > IT博文 > .NET技术 >

.NET(C#): 使用LINQ分类数据并显示在图表和列表中

时间:2013-08-04 13:11 来源:互联网 作者:源码搜藏 收藏

我们会完成这样一个程序,输入一系列的词语: 然后选择OK: 程序会统计每一个词的首字母出现次数。然后显示在图表和列表中。 列表是按出现次数降序排列的。 图表会考虑到数据太多影响直观印象,因此只显示5个数据。其中4个是出现频率最高的4个,其他的归并到

我们会完成这样一个程序,输入一系列的词语:

.NET(C#): 使用LINQ分类数据并显示在图表和列表中

 

然后选择OK:

.NET(C#): 使用LINQ分类数据并显示在图表和列表中

程序会统计每一个词的首字母出现次数。然后显示在图表和列表中。

  • 列表是按出现次数降序排列的。
  • 图表会考虑到数据太多影响直观印象,因此只显示5个数据。其中4个是出现频率最高的4个,其他的归并到“其他”这一个统一的数据项中。

 

下面是正文。

目录

  • 1. 准备工作
  • 2. 数据处理
  • 3. 界面定义
  • 4. 源代码下载

 

返回目录

1. 准备工作

首先建立一个.NET 4.5的WPF工程。我们会用到async/await,所以必须是.NET 4.5和Visual Studio 2012 IDE。

接着需要引用WPF Toolkit的相关类库。分别是:WPFToolkit.dll和System.Windows.Controls.DataVisualization.Toolkit.dll。读者也可以直接下载示例程序源代码,这两个DLL已经包含在示例程序工程中了。

 

返回目录

2. 数据处理

由于最后的分析数据要显示在图表和列表中的。所以我们要准备两套数据,然后分别绑定到图表和列表上。

数据类型全部是用的Tuple,对于列表数据。第一个数据项是组的名称,第二个数据项是组的成员,组的成员是拼接后的字符串,最终会显示在界面的TextBox中。

对于图表数据的Tuple类型。第一个数据项是图块的名称,第二个数据项是int类型,代表图块所占的比例,注意这个比例不需要自己换算成总数为100的,WPF Toolkit会自己按比例分配的。

我们这些数据统一写到一个ViewModel中,命名为ChartViewModel类型。这个类型是这样定义的:

class ChartViewModel

{

    public ChartViewModel(Tuple<stringstring>[] groups, Tuple<stringint>[] chartData)

    {

        Groups = groups;

        ChartData = chartData;

    }

 

    /// <summary>

    /// 列表的数据源

    /// </summary>

    public Tuple<stringstring>[] Groups { getprivate set; }

 

    /// <summary>

    /// 图表的数据源

    /// </summary>

    public Tuple<stringint>[] ChartData { getprivate set; }

}

 

OK,然后就是数据处理的过程,我们定义一个新的类型:ChartOperation类。这个类型专门负责数据的处理。不过在介绍ChartOperation类前,需要介绍下使用LINQ来对数据的分组和排序问题。

整个过程是这样的:我们需要首先提取每一个词的首字母,然后按照首字母分组,接着根据每个组的成员个数降序排列。最后的结果就是我们想要的。

具体如下:

1. 调用GroupBy方法按照提取的数据分组。

2. 调用OrderByDescending方法按照分组返回的IGrouping对象的Count方法分组。(IGrouping接口继承自IEnumerable接口)

 

我们可以在控制台下练习一下,这里提取的数据就是数据项本身。代码:

var ints = new int[] { 12333223 };

foreach (var group in ints.GroupBy(i => i).OrderByDescending(g => g.Count()))

{

    Console.WriteLine("{0}出现了{1}次:", group.Key, group.Count());

    Console.WriteLine("========================");

    foreach (var item in group)

        Console.WriteLine(item);

}

 

输出:

3出现了4次:

========================

3

3

3

3

2出现了3次:

========================

2

2

2

1出现了1次:

========================

1

 

ChartOperation类型就是利用上面的方法对数据进行分类和排序,然后生成图表数据和列表数据,也就是返回上面讲的ChartViewModel类型。

下面是ChartOperation类型的代码:

//+ using System.Threading.Tasks;

static class ChartOperation

{

    /// <summary>

    /// DooSync方法的异步执行。

    /// </summary>

    /// <param name="strs">需要处理的词列表</param>

    /// <param name="maxCount">图表中的最大图块数量</param>

    /// <returns></returns>

    public static async Task<ChartViewModel> DooAsync(string[] strs, int maxCount)

    {

        return await Task.Run(() => DooSync(strs, maxCount));

    }

 

    /// <summary>

    /// 同步处理数据方法。

    /// </summary>

    /// <param name="strs">需要处理的词列表</param>

    /// <param name="maxCount">图表中的最大图块数量</param>

    /// <returns></returns>

    public static ChartViewModel DooSync(string[] strs, int maxCount)

    {

        //分组,按照出现次数降序排列。

        var res = strs.GroupBy(s => s[0].ToString()).OrderByDescending(g => g.Count());

 

        //创建列表数据

        var groups = res.Select(g => Tuple.Create(g.Key, String.Join(Environment.NewLine, g))).ToArray();

 

        //创建图表数据

        var chartData = new List<Tuple<stringint>>();

 

        //对于最大值的处理

        foreach (var item in res.Take(maxCount))

            chartData.Add(new Tuple<stringint>(item.Key, item.Count()));

        if (groups.Length > maxCount)

        {

            var sum = res.Skip(maxCount).Max(i => i.Count());

            chartData.Add(Tuple.Create("其他", sum));

        }

 

        return new ChartViewModel(groups, chartData.ToArray());

    }

}

 

返回目录

3. 界面定义

数据处理逻辑完成后,就可以界面定义了。从最上方的程序截图可以看到,程序只有两个窗体。窗体具体定义就不需要讲了。挑重点讲下数据结果显示时的图表和列表定义。

图表控件在System.Windows.Controls.DataVisualization.Charting命名空间内,所以我们需要先在XAML中引用他。

xmlns:chart="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"

 

然后就可以定义Chart控件,设置Series属性,创建PieSeries对象。注意设置ItemsSource到ChartViewModel类型的ChartData属性。然后设置IndependentValuePath属性,代表图块的显示名称,对应Tuple类型的Item1。最后设置DependentValuePath属性,代表图块的大小,对应Tuple中的Item2。

所以Chart控件的XAML定义如下:

<chart:Chart>

    <chart:Chart.Series>

        <chart:PieSeries ItemsSource="{Binding ChartData}"

                        IndependentValuePath="Item1"

                        DependentValuePath="Item2"

                        IsSelectionEnabled="True"/>

    </chart:Chart.Series>

</chart:Chart>

 

对于列表显示控件,就更简单了,需要注意的是,正确绑定ChartViewModel中的数据项就OK了:

<ListBox ItemsSource="{Binding Groups}" HorizontalContentAlignment="Stretch">

    <ListBox.ItemTemplate>

        <DataTemplate>

            <Expander Header="{Binding Item1}" IsExpanded="False">

                <TextBox IsReadOnly="True" Text="{Binding Item2,Mode=OneWay}" BorderThickness="0"/>

            </Expander>

        </DataTemplate>

    </ListBox.ItemTemplate>

</ListBox>

 

然后为窗体增加一个构造函数,并在Loaded事件后调用ChartOperation类型返回的ChartViewModel对象,最后设置在DataContext属性上。注意Loaded事件执行需要加入async关键字,因为我们需要await ChartOperation类型中的Task执行。

窗体代码(ChartWindow类型代表数据显示的窗体类型):

public partial class ChartWindow : Window

{

    /// <summary>

    /// 存储词列表的字段

    /// </summary>

    string[] _strs;

 

    /// <summary>

    /// 默认构造函数(用在Designer中)

    /// </summary>

    public ChartWindow()

    {

        InitializeComponent();

    }

 

    /// <summary>

    /// 程序用到的构造函数

    /// </summary>

    /// <param name="strs">词列表</param>

    public ChartWindow(string[] strs)

        : this()

    {

        _strs = strs;

    }

 

    /// <summary>

    /// Loaded事件后,开始分析数据,注意加async关键字。

    /// </summary>

    /// <param name="sender"></param>

    /// <param name="e"></param>

    async private void Window_Loaded(object sender, RoutedEventArgs e)

    {

        if (_strs != null)

        {

            //工作中,设置IsEnabled为false。

            IsEnabled = false;

            //异步设置DataContext。

            DataContext = await ChartOperation.DooAsync(_strs, 4);

            //await后回到UI线程,设置IsEnabled为true。

            IsEnabled = true;

        }

    }

}

 

最后在主窗体的按钮Click执行上,创建并显示ChartWindow就可以了!如下代码:

//textBox变量是主窗体的TextBox控件。

if (String.IsNullOrWhiteSpace(textBox.Text))

{

    MessageBox.Show("文本不能为空");

}

 

new ChartWindow(textBox.Text.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries)).Show();

 

返回目录

4. 源代码下载

当前版本的程序和源代码下载 
下载页面 
注意:链接是微软SkyDrive页面,下载时请用浏览器直接下载,用某些下载工具可能无法下载 
程序环境:.NET Framework 4.5 
源代码环境:Microsoft Visual Studio Express 2012 for Windows Desktop


.NET技术阅读排行

最新文章