用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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM