用wpf实现简单的柱状图控件

因为最近的一个项目里需要用到柱状图,找了一些第三方的控件,UI部分定制化不强,很难保证与现有界面的统一。项目当中用到的图形也比较简单,所以干脆自己动手实现。

下面是最终的效果。

首先讲一下设计思路

  图形控件主要分为四部分:一水平文本,垂直文本,背景线条,以及最主要的柱形部分。

  第一步先绘制背景,因为水平文本和垂直文本都是根据数据源动态计算的,所以内容无法固定。为了方便计算这里以Grid控件为基类,在Grid的基础上进行绘制,因为通过添加Grid的行和列能够很好的控制控件内容的布局。

1 class WpfChart : Grid
2 {
3
4
5 .......
6
7
8 }

接下来要定义控件的数据源。柱状图的数据源比较简单,可以通过简单的键值对进行设计。为了方便绑定,这里将数据源设计为依赖属性

 1 public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable<KeyValuePair<string, double>>), typeof(WpfChart), new PropertyMetadata(new List<KeyValuePair<string,double>>(), OnItemsSourcePropertyChanged));
 2
 3 public IEnumerable<KeyValuePair<string,double>> ItemsSource
 4 {
 5     get { return (List<KeyValuePair<string, double>>)GetValue(ItemsSourceProperty); }
 6     set { SetValue(ItemsSourceProperty, value); }
 7 }

为了方便布局,这里将整个控件划分成三个区域,分别用三个Grid控件进行管理这三块区域的内容。

1 private readonly Grid _gridTextH = new Grid();
2 private readonly Grid _gridTextV = new Grid();
3 private readonly Grid _gridContent = new Grid();

下面进行垂直、水平内容的添加 ,垂直文本通通放到_gridTextH控件内,水平文本通通放到_gridTextV控件内。

1、通过获取数据源中的最大值,计算控件中需要显示的行数。

2、添加对应的表格线到_gridTextH中。

3、通过获取数据源的长度,添加控件对应的水平文本。

 1         void DrawHTextCollection()
 2         {
 3             _gridTextH.ColumnDefinitions.Clear();
 4             _gridTextH.RowDefinitions.Clear();
 5             _gridTextH.Children.Clear();
 6             _gridTextH.Margin = new Thickness(_viewPortPad.Left, 0, 0, 0);
 7             _gridTextH.RowDefinitions.Add(new RowDefinition() {Height = new GridLength(1, GridUnitType.Star)});
 8             _gridTextH.RowDefinitions.Add(new RowDefinition()
 9             {
10                 Height = new GridLength(_viewPortPad.Bottom, GridUnitType.Pixel)
11             });
12
13             TextBlock tb;
14
15             foreach (var v in ItemsSource)
16             {
17                 _gridTextH.Children.Add(
18                     tb =
19                         new TextBlock()
20                         {
21                             Text = v.Key,
22                             HorizontalAlignment = HorizontalAlignment.Center,
23                             VerticalAlignment = VerticalAlignment.Top,
24                             Margin = new Thickness(0, 10, 0, 0)
25
26                         });
27                 _gridTextH.ColumnDefinitions.Add(new ColumnDefinition());
28                 Grid.SetRow(tb, 1);
29                 Grid.SetColumn(tb, _gridTextH.ColumnDefinitions.Count - 1);
30             }
31         }
32
33
34
35
36        void DrawVTextCollection()
37         {
38             TextBlock tb;
39             Border border;
40             _gridTextV.RowDefinitions.Clear();
41             _gridTextV.Children.Clear();
42             _gridTextV.ColumnDefinitions.Clear();
43             _gridTextV.Margin = new Thickness(0, _viewPortPad.Top, 0, _viewPortPad.Bottom);
44             _gridTextV.ColumnDefinitions.Add(new ColumnDefinition()
45             {
46                 Width = new GridLength(_viewPortPad.Left, GridUnitType.Pixel)
47             });
48             _gridTextV.ColumnDefinitions.Add(new ColumnDefinition()
49             {
50                 Width = new GridLength(1, GridUnitType.Star)
51             });
52             foreach (var v in GetVTextCollection())
53             {
54                 _gridTextV.Children.Add(
55                     tb =
56                         new TextBlock()
57                         {
58                             Text = v.ToString(),
59                             Margin = new Thickness(0, 0, 5, 0),
60                             HorizontalAlignment = HorizontalAlignment.Right,
61                             VerticalAlignment = VerticalAlignment.Bottom
62                         });
63                 _gridTextV.Children.Add(
64                     border =
65                         new Border()
66                         {
67                             BorderBrush = new SolidColorBrush((Color) ColorConverter.ConvertFromString("#FFc0c0c0")),
68                             BorderThickness = new Thickness(0, 0, 0, 1),
69                             VerticalAlignment = VerticalAlignment.Bottom
70                         });
71                 _gridTextV.RowDefinitions.Add(new RowDefinition());
72                 Grid.SetRow(tb, _gridTextV.RowDefinitions.Count - 1);
73                 Grid.SetColumn(border, 1);
74                 Grid.SetRow(border, _gridTextV.RowDefinitions.Count - 1);
75             }
76         }

下面是背景生成后的效果图。

最后就是最重要的内容区域了。通通放到_gridContent中。

 1 void DrawCoordinate()
 2 {
 3     Rectangle rectangle;
 4     TextBlock tb;
 5     _gridContent.ColumnDefinitions.Clear();
 6     _gridContent.RowDefinitions.Clear();
 7     _gridContent.Children.Clear();
 8
 9     //_gridContent.Margin = new Thickness(_viewPortPad.Left, 0, 0, _viewPortPad.Bottom);
10     _gridContent.ColumnDefinitions.Add(new ColumnDefinition()
11     {
12         Width = new GridLength(_viewPortPad.Left, GridUnitType.Pixel)
13     });
14     _gridContent.RowDefinitions.Add(new RowDefinition()
15     {
16         Height = new GridLength(1, GridUnitType.Star)
17     });
18     _gridContent.RowDefinitions.Add(new RowDefinition()
19     {
20         Height = new GridLength(_viewPortPad.Bottom, GridUnitType.Pixel)
21     });
22
23     var maxHeight = _gridContent.ActualHeight - _viewPortPad.Top - _viewPortPad.Bottom;
24     var maxWidth = _gridContent.ActualWidth - _viewPortPad.Left;
25
26     var list = ItemsSource;
27     foreach (var v in list)
28     {
29         var xx = maxHeight*(v.Value/_chartMaxNumber);
30         _gridContent.Children.Add(
31             rectangle =
32                 new Rectangle()
33                 {
34                     Fill = _defaultBrush,
35                     Height = maxHeight*(v.Value/_chartMaxNumber),
36                     Width = maxWidth/list.Count()*0.6,
37                     VerticalAlignment = VerticalAlignment.Bottom
38                 });
39         var doubleAnimation = new DoubleAnimation(0, maxHeight*(v.Value/_chartMaxNumber),
40             new Duration(new TimeSpan(0, 0, 0, 0, 1000)));
41
42         rectangle.BeginAnimation(Rectangle.HeightProperty, doubleAnimation);
43
44         rectangle.Tag = v.Value;
45
46         if (v.Value == this._maxValue)
47             rectangle.Fill = _maxValueBrush;
48         _gridContent.Children.Add(
49             tb =
50                 new TextBlock()
51                 {
52                     Text = v.Value.ToString("f"),
53                     Margin = new Thickness(0, 0, 0, maxHeight*(v.Value/_chartMaxNumber) + 5),
54                     VerticalAlignment = VerticalAlignment.Bottom,
55                     HorizontalAlignment = HorizontalAlignment.Center,
56
57                 }
58             );
59
60
61         var thicknessAnimation = new ThicknessAnimation(new Thickness(0, 0, 0, 0),
62             new Thickness(0, 0, 0, maxHeight*(v.Value/_chartMaxNumber) + 5),
63             new Duration(new TimeSpan(0, 0, 0, 0, 1000)));
64         tb.BeginAnimation(TextBlock.MarginProperty, thicknessAnimation);
65
66         rectangle.MouseEnter += Rectangle_MouseEnter;
67         rectangle.MouseLeave += Rectangle_MouseLeave;
68         _gridContent.ColumnDefinitions.Add(new ColumnDefinition());
69         Grid.SetColumn(rectangle, _gridContent.ColumnDefinitions.Count - 1);
70         Grid.SetColumn(tb, _gridContent.ColumnDefinitions.Count - 1);
71     }
72 }

生成的控件功能虽然简单,但定制化很强,任何地方都能修改,摆脱了使用第三方控件的束缚。

代码位置:http://download.csdn.net/detail/shushukui/9512216

时间: 2024-09-28 03:00:41

用wpf实现简单的柱状图控件的相关文章

转载 [WPF][C#]在WPF中内嵌WindowsForm控件-使用WindowsFormsControlLibrary

[WPF][C#]在WPF中内嵌WindowsForm控件-使用WindowsFormsControlLibrary 在[WPF][C#]在WPF中内嵌WindowsForm控件一文中为各位介绍了直接在WPF中使用XAML来嵌入Windows Form控件的作法,不过不是每个人都喜欢写XAML,而且有时候会需要把已经存在的Windows Form应用程序嵌入到WPF中,所以这次就来跟大家介绍怎么使用参考dll档的方式,把dll中的Windows Form加到WPF中. 都说了要使用Windows

WPF 10天修炼 - 内容控件

WPF内容控件 在WPF中,所有呈现在用户界面上的对象都称为用户界面元素.但是只有派生自System.Windows.Controls.Control类的对象才称为控件.内容控件通常是指具有Content属性的控件,Content属性并非定义在每个控件中,而是定义在基类System.Windows.Controls命名空间的ContentControl类中.注意:Content属性只接收单个内容元素. WPF内容控件分类 1.  直接继承ContentControl的控件 2.  继承Heade

Stimulsoft Reports.Wpf是针对WPF开发的报表工具控件

Stimulsoft Reports.Wpf是针对WPF开发的报表工具控件.无需上网,所有的WPF功能都能用上!丰富的界面更换功能.查看功能.打印以及导出报表功能——所有的这一切就是它都能轻松实现. 创建Stimulsoft Reports.Wpf是基于Stimulsoft团队多年开发以及使用的报表引擎来创建报表.只需简单的几行代码即可执行报表复杂的操作,报表引擎提供了创建报表的许多功能.大量的组件开发包,独特的一套属性和参数,精心构思的报表体系.很多选项都是绝对独特且仅出现该产品中.Stimu

《深入浅出WPF》学习总结之控件与布局

一.控件到底是什么 控件的本质是“数据+算法”——用户输入原始数据,算法处理原始数据并得到结果数据.问题就在于程序如何将结果数据展示给用户.同样一组数据,你可以使用LED阵列显示出来,或者是以命令行模式借助各种控制字符(如Tab)对其并输出,但这些都不如图形化用户界面(Graphics User Interface ,GUI)来的友好和方便.GUI是程序界的优胜者,但在Windows上实现图形化界面有很多中方法.每种方法又拥有自己的一套开发理念和工具.每种GUI开发与它的里理念和工具共同组成一种

.NET CORE(C#) WPF 方便的实现用户控件切换(祝大家新年快乐)

微信公众号:Dotnet9,网站:Dotnet9,问题或建议:请网站留言, 如果对您有所帮助:欢迎赞赏. .NET CORE(C#) WPF 方便的实现用户控件切换(祝大家新年快乐) 快到2020年了,祝大家新年快乐,今年2019最后一更,谢谢大家支持! 阅读导航 本文背景 代码实现 本文参考 源码 1. 本文背景 一个系统主界面,放上一个菜单,点击菜单在客户区切换不同的展示界面,这是很常规的设计,见下面展示效果图: 左侧一个菜单,点击菜单,右侧切换界面,界面切换动画使用MD控件的组件实现(自己

简单测试用控件.

props.push('{"prop":"x","min":-100,"max":100}'); props.push('{"prop":"y","min":-100,"max":100}'); props.push('{"prop":"scaleX","min":-1,"max

如何在Android实现桌面清理内存简单Widget小控件

如何在Android实现桌面清理内存简单Widget小控件 我们经常会看到类似于360.金山手机卫士一类的软件会带一个widget小控件,显示在桌面上,上面会显示现有内存大小,然后会带一个按键功能来一键清理内存,杀死后台进程的功能,那么这个功能是如何实现的呢,我们今天也来尝试做一个类似的功能的小控件. 效果图: 一.UI部分的编写: 参照Google的文档,首先在建立一个类继承AppWidgetProvider import android.appwidget.AppWidgetProvider

时间控件-简单的时间控件

<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title></title> <script src="Scripts/jquery-1.10.2.js"><

WPF编程之自定义Button控件样式

自.NET Framework 3.0 以后,WPF编程框架可使开发人员开发出更加令人耳目一新的桌面应用程序.它使开发工作更加方便快捷,它将设计人员和编程人员的工作分离开来.至于WPF的背景历史.框架特点.框架结构这里就不再赘述.有兴趣的同袍可在百度搜索关于WPF的相关知识介绍,如WPF. 在微软在WPF框架里提供了一些基础功能各异的控件,例如Button.TextBox.Label.Panel.TextBlock等等.微软将这些组件可视化集成到Visual Studio集成开发工具中了,这在实