(一)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 允许用户点击一个标题,展开或收起其中包含的内容,用于显示隐藏部分信息。

水平初步

image
image

纵向

image

均分
最外层是容器不是border
image

折线图

最外层是容器不是border,所以不可以用itemscontrol实现,因为不好画点与点之间的连线,是在不同的小容器中,所以选择canvas画布、grid等没有分区的

Collapsed 使控件完全隐藏,不显示在界面上,且不占据布局空间。
Hidden 也使控件不可见,但占据布局空间。
Visible 表示控件可见,并且显示在界面上。

Polyline 控件用于绘制一条折线,且方便填充颜色到下面的区域
points是依赖属性(类型PointCollection),支持绑定,
image
但是没有实现INotifyPropertyChanged就没有办法实现依赖属性的通知更新

INotifyPropertyChanged 接口是.NET框架中的接口,用于在属性值发生更改时通知监听器。这个接口通常用于实现数据绑定和界面更新的机制,特别适用于MVVM模式(Model-View-ViewModel)中。

类型PointCollection不支持继承扩展,所以也不好添加接口实现
解决办法只有-->依赖附加属性

vm层的points提供数据给PointHelper,然后PointHelper需要处理交给控件,用值改变的回调函数处理
image
image
vm
image

热力图

image
vm
image
自定义组件实现

  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;
 }
posted @ 2024-04-10 16:42  huihui不会写代码  阅读(70)  评论(0)    收藏  举报