(一)WPF自定义实现
概述
winform :chart(性能问题)
WPF:需要自己实现或用第三方库
数据驱动模式
图表:直方图、折线图、热力图
直方图
自定义实现
容器
- Grid(网格): Grid 是WPF中最常用的容器控件之一,用于将控件按行和列的方式进行布局。可以设置行和列的大小、对齐方式等。
- StackPanel(堆栈面板): StackPanel 将子控件按照水平或垂直的堆栈方式排列。可以设置子控件的对齐方式、间距等。
- WrapPanel(自动换行面板): WrapPanel 按照水平或垂直的方式排列子控件,当空间不足时自动换行。
- Canvas(画布): Canvas 允许子控件通过绝对位置布局,子控件可以自由定位在画布上的任何位置。
- DockPanel(停靠面板): DockPanel 使子控件停靠在面板的四个边缘(上、下、左、右)或中间位置。
- UniformGrid(均匀网格): UniformGrid 将子控件均匀地分布在网格中的多个单元格中,每个单元格大小相等。
- Border(边框): Border 可以用来给子控件添加边框,并可以设置边框颜色、厚度、圆角等属性。
- GroupBox(分组框): GroupBox 主要用于对一组相关控件进行分组,并可以添加标题以区分不同的组。
- TabControl(选项卡): TabControl 允许将相关内容分组在不同的选项卡中,用户可以通过切换选项卡来查看不同内容。
- Expander(展开器): Expander 允许用户点击一个标题,展开或收起其中包含的内容,用于显示隐藏部分信息。
水平初步


纵向

均分
最外层是容器不是border

折线图
最外层是容器不是border,所以不可以用itemscontrol实现,因为不好画点与点之间的连线,是在不同的小容器中,所以选择canvas画布、grid等没有分区的
Collapsed 使控件完全隐藏,不显示在界面上,且不占据布局空间。
Hidden 也使控件不可见,但占据布局空间。
Visible 表示控件可见,并且显示在界面上。
Polyline 控件用于绘制一条折线,且方便填充颜色到下面的区域
points是依赖属性(类型PointCollection),支持绑定,

但是没有实现INotifyPropertyChanged就没有办法实现依赖属性的通知更新
INotifyPropertyChanged 接口是.NET框架中的接口,用于在属性值发生更改时通知监听器。这个接口通常用于实现数据绑定和界面更新的机制,特别适用于MVVM模式(Model-View-ViewModel)中。
类型PointCollection不支持继承扩展,所以也不好添加接口实现
解决办法只有-->依赖附加属性
vm层的points提供数据给PointHelper,然后PointHelper需要处理交给控件,用值改变的回调函数处理


vm

热力图

vm

自定义组件实现
public class HeatMapChart:FrameworkElement
{
public double[,] Values
{
get { return (double[,])GetValue(ValuesProperty); }
set { SetValue(ValuesProperty, value); }
}
// Using a DependencyProperty as the backing store for Values. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ValuesProperty =
DependencyProperty.Register("Values", typeof(double[,]), typeof(HeatMapChart), new PropertyMetadata(null,new PropertyChangedCallback(OnValuesChanged)));
private static void OnValuesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as HeatMapChart).InvalidateVisual();//让他视觉效果失效,就会重绘
}
//OnRender 方法会在控件需要重新绘制时被调
//例如绘制自定义的形状、图标、文本或其他图形元素
// OnRender 方法是一个高性能的方法,因此建议在此方法中仅执行必要的绘制操作,以保持绘制效率
protected override void OnRender(DrawingContext drawingContext)
{ //DrawingContext在 WPF 中进行图形绘制的主要类之一
if (Values==null) return;
base.OnRender(drawingContext);
//获取行列
var rowCount=Values.GetLength(0);
var colCount=Values.GetLength(1);
//把当前绘制尺寸拿到
Size renderSize=base.RenderSize;
//计算每一块宽高
double perWidth=renderSize.Width/colCount;
double perHeight=renderSize.Height/rowCount;
for(int i=0; i< colCount; i++)
{
for(int j=0; j<rowCount; j++)
{
drawingContext.DrawRectangle(GetColor(Values[j, i]), null, new Rect(i * perWidth + 0.5, j * perHeight + 0.5, perWidth - 1, perHeight - 1));
}
}
}
private Brush GetColor(double value)
{
//根据温度显示颜色
if (value > 100)
return Brushes.Red;
else if(value>90)
return Brushes.Orange;
else if (value > 60)
return Brushes.Pink;
return Brushes.LightBlue;
}
}
生成二维数组数值的算法:模拟温度
//生成了包含特定规律的数据值,这种数据生成方式可以应用于数据可视化、图形渲染等领域。
private double[,] CreateSeries(int index,int width,int height,double cpMin,double cpMax)
{
double[,] result = new double[height,width];
double angle = Math.Round(Math.PI*2*index,3)/30;
//表示对计算出的结果进行四舍五入保留 3 位小数
int w=width; int h=height;
for (int x = 0; x < w; x++)
//Parallel.For(0,w,x=>
{
for (int y = 0; y< h; y++)
//Parallel.For(0,h,y=>
{
var v = (1 + Math.Round(Math.Sin(x * 0.04 + angle), 3)) * 50 + (1 + Math.Round(Math.Sin(y * 0.1 + angle), 3)) * 50 * (1 + Math.Round(Math.Sin(angle * 2 + angle), 3));
var cx = w / 2;
var cy = h / 2;
var r=Math.Sqrt((x-cx)* (x - cx) + (y-cy)* (y - cy));
var exp = Math.Max(0, 1 - r * 0.008);
var zValue = v * exp + random.NextDouble() * 50;
result[y,x] = (zValue>cpMax)?cpMax:zValue;
}
}
return result;
}


浙公网安备 33010602011771号