因为最近的一个项目里需要用到柱状图,找了一些第三方的控件,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