1.前言
最近有好一阵子没有写文章了,这几天无聊写了一个主要用于MVVM绑定的自定义RectangleChart柱状图形控件,主要模仿Chart图形中的数据显示。这里跟大家分享下自定义RectangleChart柱状图形控件的思路和心得。
2.功能: 以下图片为自定义RectangleChart柱状体控件的详细功能。
刻度表 :通过刻度表可以让整个控件的图形数据显示更加直观。
刻度列表:显示图形中的所有刻度。
刻度值 :标记整个图形中各个刻度的进制位(如图形中所示,进制位为10)。
柱状体 :数据的柱状图形表示。
柱状体值:具体的数据值。
数据列表:整个图形中的所有数据。



private string _lineColor = "#D3E5FF"; //刻度列表线颜色
private double ChartMaxYValue = 100; //Y轴最大值
private double ChartMaxXValue { get; set; } //X轴最大值
private int leftMargin = 100; //面板左边框
private int rightMargin = 100; //面板右边框
private int topMargin = 20; //面板上边框
private int bottomMargin = 20; //面板下边框
private int leftChartMargin = 20; //具体图形的左边框
private int rightChartMargin = 20; //具体图形的右边框
private int ySize = 40; //Y轴线间距
private int xSize = 50; //X轴线间距
private int startY = 20; //Y轴起点
private int endY = 460; //Y轴结束点
private int startX = 0; //X轴起点
private int endX = 100; //Y轴起点
private double yStepSize = 0.8; //Y轴的进位制
private int chartWidth = 40; //图形宽度
private double ChartMaxYValue = 100; //Y轴最大值
private double ChartMaxXValue { get; set; } //X轴最大值
private int leftMargin = 100; //面板左边框
private int rightMargin = 100; //面板右边框
private int topMargin = 20; //面板上边框
private int bottomMargin = 20; //面板下边框
private int leftChartMargin = 20; //具体图形的左边框
private int rightChartMargin = 20; //具体图形的右边框
private int ySize = 40; //Y轴线间距
private int xSize = 50; //X轴线间距
private int startY = 20; //Y轴起点
private int endY = 460; //Y轴结束点
private int startX = 0; //X轴起点
private int endX = 100; //Y轴起点
private double yStepSize = 0.8; //Y轴的进位制
private int chartWidth = 40; //图形宽度


/// <summary>
/// 取DataSource最大值
/// </summary>
public void MeasuneValue()
{
if (DataSource != null)
{
double max = 0;
foreach(var data in DataSource)
{
if (data.ChartValue > max)
{
max = data.ChartValue;
}
}
ChartMaxYValue = GetMaxYValue(max);
}
}
/// <summary>
/// 获取最大进位制(如60返回100 4返回10)
/// </summary>
/// <param name="max">最大值</param>
/// <returns>最大进位制</returns>
public double GetMaxYValue(double max)
{
int valueTime = (int)Math.Log10(max); //计算出最大的进位制
return Math.Pow(10, valueTime+1);
}
/// 取DataSource最大值
/// </summary>
public void MeasuneValue()
{
if (DataSource != null)
{
double max = 0;
foreach(var data in DataSource)
{
if (data.ChartValue > max)
{
max = data.ChartValue;
}
}
ChartMaxYValue = GetMaxYValue(max);
}
}
/// <summary>
/// 获取最大进位制(如60返回100 4返回10)
/// </summary>
/// <param name="max">最大值</param>
/// <returns>最大进位制</returns>
public double GetMaxYValue(double max)
{
int valueTime = (int)Math.Log10(max); //计算出最大的进位制
return Math.Pow(10, valueTime+1);
}


/// <summary>
/// 画Y轴的线条
/// </summary>
/// <param name="container"></param>
public void DrawYLine(Canvas container)
{
var x2Value = leftMargin + (DataSource.Count+1) * xSize;
for (int i = 0; i < 12; i++)
{
container.Children.Add(new Line { X1 = leftMargin, Y1 = topMargin + (i * ySize), X2 = x2Value, Y2 = topMargin + (i * ySize), Stroke = new SolidColorBrush(ChartLineColor) });
}
}
/// <summary>
/// 画X轴的线条
/// </summary>
/// <param name="container"></param>
public void DratXLine(Canvas container)
{
for (int i = 0; i < DataSource.Count+2;i++ )
{
var xValue = leftMargin + (i * xSize);
container.Children.Add(new Line { X1 = xValue, Y1 = startY, X2 = xValue, Y2 = endY, Stroke = new SolidColorBrush(ChartLineColor) });
}
}
/// 画Y轴的线条
/// </summary>
/// <param name="container"></param>
public void DrawYLine(Canvas container)
{
var x2Value = leftMargin + (DataSource.Count+1) * xSize;
for (int i = 0; i < 12; i++)
{
container.Children.Add(new Line { X1 = leftMargin, Y1 = topMargin + (i * ySize), X2 = x2Value, Y2 = topMargin + (i * ySize), Stroke = new SolidColorBrush(ChartLineColor) });
}
}
/// <summary>
/// 画X轴的线条
/// </summary>
/// <param name="container"></param>
public void DratXLine(Canvas container)
{
for (int i = 0; i < DataSource.Count+2;i++ )
{
var xValue = leftMargin + (i * xSize);
container.Children.Add(new Line { X1 = xValue, Y1 = startY, X2 = xValue, Y2 = endY, Stroke = new SolidColorBrush(ChartLineColor) });
}
}


/// <summary>
/// 画Y轴上的数值
/// </summary>
/// <param name="container"></param>
public void DrawYValue(Canvas container)
{
for (int i = 0; i <=10; i++)
{
double value = i * ChartMaxYValue / 10;
TextBlock t = new TextBlock {Text = value.ToString(),Foreground = ValueForeground};
t.Width = 80;
t.TextAlignment = TextAlignment.Right;
Canvas.SetLeft(t,10);
Canvas.SetTop(t,50+(10-i)*ySize);
MainContainer.Children.Add(t);
}
}
/// 画Y轴上的数值
/// </summary>
/// <param name="container"></param>
public void DrawYValue(Canvas container)
{
for (int i = 0; i <=10; i++)
{
double value = i * ChartMaxYValue / 10;
TextBlock t = new TextBlock {Text = value.ToString(),Foreground = ValueForeground};
t.Width = 80;
t.TextAlignment = TextAlignment.Right;
Canvas.SetLeft(t,10);
Canvas.SetTop(t,50+(10-i)*ySize);
MainContainer.Children.Add(t);
}
}


/// <summary>
/// 画图形
/// </summary>
/// <param name="container"></param>
public void DrawChart(Canvas container)
{
container.Width = leftMargin + DataSource.Count * chartWidth * 2 + rightMargin;
for (int i = 0; i < DataSource.Count; i++)
{
//LinearGradientBrush brush = new LinearGradientBrush();
//GradientStopCollection c = new GradientStopCollection();
//c.Add(new GradientStop { Color = GetRandomColor(),Offset=0.0});
//c.Add(new GradientStop { Color = GetRandomColor(), Offset = 1.0});
//brush.GradientStops = c;
Rectangle rect = new Rectangle
{
Width = chartWidth,
Height = DataSource[i].ChartValue * yStepSize,
Fill = new SolidColorBrush(GetRandomColor()),
ToolTip = DataSource[i].ChartValue.ToString()
};
rect.RadiusX = 5;
rect.RadiusY = 5;
Canvas.SetLeft(rect, leftMargin + (leftChartMargin + leftChartMargin / 2) + i * (chartWidth + rightChartMargin / 2));
Canvas.SetTop(rect, endY - rect.Height);
MainContainer.Children.Add(rect);
}
}
/// 画图形
/// </summary>
/// <param name="container"></param>
public void DrawChart(Canvas container)
{
container.Width = leftMargin + DataSource.Count * chartWidth * 2 + rightMargin;
for (int i = 0; i < DataSource.Count; i++)
{
//LinearGradientBrush brush = new LinearGradientBrush();
//GradientStopCollection c = new GradientStopCollection();
//c.Add(new GradientStop { Color = GetRandomColor(),Offset=0.0});
//c.Add(new GradientStop { Color = GetRandomColor(), Offset = 1.0});
//brush.GradientStops = c;
Rectangle rect = new Rectangle
{
Width = chartWidth,
Height = DataSource[i].ChartValue * yStepSize,
Fill = new SolidColorBrush(GetRandomColor()),
ToolTip = DataSource[i].ChartValue.ToString()
};
rect.RadiusX = 5;
rect.RadiusY = 5;
Canvas.SetLeft(rect, leftMargin + (leftChartMargin + leftChartMargin / 2) + i * (chartWidth + rightChartMargin / 2));
Canvas.SetTop(rect, endY - rect.Height);
MainContainer.Children.Add(rect);
}
}


/// <summary>
/// 画数据列表值
/// </summary>
/// <param name="container"></param>
public void DrawXValue(Canvas container)
{
container.Width = leftMargin + DataSource.Count * chartWidth * 2 + rightMargin;
for (int i = 0; i < DataSource.Count; i++)
{
TextBlock t = new TextBlock
{
Margin = new Thickness(5),
Text = DataSource[i].Name,
TextAlignment = TextAlignment.Center,
Foreground = TitleForeground
};
t.RenderTransform = new RotateTransform { CenterX =5,CenterY=5,Angle = 60 };
Canvas.SetLeft(t, leftMargin +10 + (leftChartMargin + leftChartMargin / 2) + i * (chartWidth + rightChartMargin / 2));
Canvas.SetTop(t, endY);
MainContainer.Children.Add(t);
}
}
/// 画数据列表值
/// </summary>
/// <param name="container"></param>
public void DrawXValue(Canvas container)
{
container.Width = leftMargin + DataSource.Count * chartWidth * 2 + rightMargin;
for (int i = 0; i < DataSource.Count; i++)
{
TextBlock t = new TextBlock
{
Margin = new Thickness(5),
Text = DataSource[i].Name,
TextAlignment = TextAlignment.Center,
Foreground = TitleForeground
};
t.RenderTransform = new RotateTransform { CenterX =5,CenterY=5,Angle = 60 };
Canvas.SetLeft(t, leftMargin +10 + (leftChartMargin + leftChartMargin / 2) + i * (chartWidth + rightChartMargin / 2));
Canvas.SetTop(t, endY);
MainContainer.Children.Add(t);
}
}


/// <summary>
/// 数据标题颜色
/// </summary>
public static readonly DependencyProperty TitleForegroundProperty = DependencyProperty.Register("TitleForeground",typeof(SolidColorBrush),typeof(RectangeChart),new PropertyMetadata(Brushes.Brown));
public SolidColorBrush TitleForeground
{
get { return (SolidColorBrush)GetValue(TitleForegroundProperty); }
set
{
SetValue(TitleForegroundProperty,value);
}
}
/// <summary>
/// 刻度列表颜色
/// </summary>
public static readonly DependencyProperty ValueForegroundProperty = DependencyProperty.Register("ValueForeground", typeof(SolidColorBrush), typeof(RectangeChart), new PropertyMetadata(Brushes.Black));
public SolidColorBrush ValueForeground
{
get { return (SolidColorBrush)GetValue(ValueForegroundProperty); }
set
{
SetValue(ValueForegroundProperty, value);
}
}
/// 数据标题颜色
/// </summary>
public static readonly DependencyProperty TitleForegroundProperty = DependencyProperty.Register("TitleForeground",typeof(SolidColorBrush),typeof(RectangeChart),new PropertyMetadata(Brushes.Brown));
public SolidColorBrush TitleForeground
{
get { return (SolidColorBrush)GetValue(TitleForegroundProperty); }
set
{
SetValue(TitleForegroundProperty,value);
}
}
/// <summary>
/// 刻度列表颜色
/// </summary>
public static readonly DependencyProperty ValueForegroundProperty = DependencyProperty.Register("ValueForeground", typeof(SolidColorBrush), typeof(RectangeChart), new PropertyMetadata(Brushes.Black));
public SolidColorBrush ValueForeground
{
get { return (SolidColorBrush)GetValue(ValueForegroundProperty); }
set
{
SetValue(ValueForegroundProperty, value);
}
}


<UserControl x:Class="SmlAnt.Library.Views.ControlsTest.RectangeChart"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:Controls="clr-namespace:SmlAnt.Library.Controls"
d:DesignHeight="300" d:DesignWidth="300" >
<Grid>
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Controls:RectangeChart DataSource="{Binding DataSource}" TitleForeground="Brown" ValueForeground="Black"/>
</ScrollViewer>
</Grid>
</UserControl>
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:Controls="clr-namespace:SmlAnt.Library.Controls"
d:DesignHeight="300" d:DesignWidth="300" >
<Grid>
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Controls:RectangeChart DataSource="{Binding DataSource}" TitleForeground="Brown" ValueForeground="Black"/>
</ScrollViewer>
</Grid>
</UserControl>


public class RectangleChartViewModel:ViewModelBase
{
Random random = new Random();
private List<Controls.ChartData> _dataSource;
public List<Controls.ChartData> DataSource
{
get { return _dataSource; }
set
{
if (_dataSource != value)
{
_dataSource = value;
RaisePropertyChanged("DataSource");
}
}
}
public RectangleChartViewModel()
{
var temp = new List<Controls.ChartData> { };
for (int i = 1; i <= 10; i++)
{
Controls.ChartData data = new Controls.ChartData
{
ChartValue = random.Next(40,100),
Name = "数据"+i.ToString()
};
temp.Add(data);
}
DataSource = temp;
}
}
{
Random random = new Random();
private List<Controls.ChartData> _dataSource;
public List<Controls.ChartData> DataSource
{
get { return _dataSource; }
set
{
if (_dataSource != value)
{
_dataSource = value;
RaisePropertyChanged("DataSource");
}
}
}
public RectangleChartViewModel()
{
var temp = new List<Controls.ChartData> { };
for (int i = 1; i <= 10; i++)
{
Controls.ChartData data = new Controls.ChartData
{
ChartValue = random.Next(40,100),
Name = "数据"+i.ToString()
};
temp.Add(data);
}
DataSource = temp;
}
}
5.总结:
这个自定义RectangleChart的开发只是一个简单的而且不完善的控件开发,只是凭借自己的一种兴趣和思路的分享。希望能够给大家带来一些帮助。同时也欢迎园子里的朋友多提出一些宝贵的意见。共同讨论、共同进步、一起分享。