将OxyPlot封装成用户控件后在WPF中的应用

news2024/11/14 2:21:56

1、文件架构
在这里插入图片描述
2、加载依赖项
Newtonsoft.Json
OxyPlot.Wpf
3、NotifyBase.cs

namespace Accurate.Common
{
    public class NotifyBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
        public void DoNotify([CallerMemberName] string prppertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prppertyName));
        }
    }
}

4、CartesianChartViewModel.cs

namespace Accurate.Controls.ViewModels
{
    public class CartesianChartViewModel:NotifyBase
    {
		/// <summary>
		/// 定义plot属性
		/// </summary>
		private PlotModel? plotModel;

		public PlotModel? PlotModel
        {
			get { return plotModel; }
			set { plotModel = value; this.DoNotify(); }
		}
		/// <summary>
		/// 构造函数
		/// </summary>
		public CartesianChartViewModel()
		{
            PlotModel=new PlotModel();
        }
    }
}

5、CartesianChart.xaml

<UserControl x:Class="Accurate.Controls.CartesianChart"
             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" 
             xmlns:local="clr-namespace:Accurate.Controls"
             xmlns:oxy="http://oxyplot.org/wpf"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Border Name="Layout" BorderBrush="#DDD" BorderThickness="1" CornerRadius="10" Background="LightBlue">
        <Border.Effect>
            <DropShadowEffect Color="#F2F2F2" ShadowDepth="10" BlurRadius="10" Opacity="0.4" Direction="270"/>
        </Border.Effect>
        <oxy:PlotView x:Name="PlotView" Model="{Binding Path= PlotModel}"></oxy:PlotView>
    </Border>
</UserControl>

6、CartesianChart.xaml.cs

namespace Accurate.Controls
{
    /// <summary>
    /// CartesianChart.xaml 的交互逻辑
    /// </summary>
    public partial class CartesianChart : UserControl
    {
        //Plot
        public CartesianChartViewModel? viewModel;
        //曲线数组
        public LineSeries[] lineSeries;
        /// <summary>
        /// 曲线属性设置属性
        /// </summary>
        public string ChartSetStr
        {
            get { return (string)GetValue(ChartSetStrProperty); }
            set { SetValue(ChartSetStrProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ChartSetStrProperty =
            DependencyProperty.Register("ChartSetStr", typeof(string), typeof(CartesianChart), 
                new PropertyMetadata(default(string),new PropertyChangedCallback(OnSetPropertyChanged)));
        /// <summary>
        /// 设置改变处理
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnSetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if(d is CartesianChart)
            {
                CartesianChart chart = (CartesianChart)d;
                chart.CreatePlot();
            }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        public CartesianChart()
        {
            InitializeComponent();
            this.Loaded += CartesianChart_Loaded;
            Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;
        }
        /// <summary>
        /// 退出时释放资源
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Dispatcher_ShutdownStarted(object? sender, EventArgs e)
        {
            //timer?.Stop();
        }
        /// <summary>
        /// 控件加载
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CartesianChart_Loaded(object sender, RoutedEventArgs e)
        {
            CreatePlot();
        }
        /// <summary>
        /// 获取轴名称
        /// </summary>
        /// <param name="axisType"></param>
        /// <returns></returns>
        private string GetAxisKey(AxisType axisType)
        {
            string str = "";
            switch (axisType)
            {
                case AxisType.X:
                    str = "x";
                    break;
                case AxisType.Y:
                    str = "y";
                    break;
                case AxisType.X1:
                    str = "x1";
                    break;
                case AxisType.Y1:
                    str = "y1";
                    break;
            }
            return str;
        }
        /// <summary>
        /// 轴设置
        /// </summary>
        /// <param name="axisItemModels"></param>
        private void LinearAxisSet(ObservableCollection<AxisItemModel> axisItemModels)
        {
            if(axisItemModels != null && axisItemModels.Count > 1)
            {
                for(int i = 0; i < axisItemModels.Count; i++)
                {
                    var axis = new LinearAxis();
                    //设置轴类型
                    axis.Title = axisItemModels[i].Name;
                    axis.Key = GetAxisKey(axisItemModels[i].Type);
                    axis.Position = axisItemModels[i].Position;
                    //axis.Minimum = axisItemModels[i].Minimum;
                    //axis.MajorStep = axisItemModels[i].Step;
                    //axis.Maximum = axisItemModels[i].Maximum;
                    viewModel?.PlotModel?.Axes.Add(axis);
                }
            }
        }
        /// <summary>
        /// 曲线设置
        /// </summary>
        /// <param name="curveItemModels"></param>
        private void LineSeriesSet(ObservableCollection<CurveItemModel> curveItemModels)
        {
            if(curveItemModels != null && curveItemModels.Count > 1)
            {
                lineSeries = new LineSeries[curveItemModels.Count];
                for (int i=0;i<curveItemModels.Count;i++)
                {
                    lineSeries[i]=new LineSeries();
                    lineSeries[i].Title = curveItemModels[i].Name;
                    lineSeries[i].YAxisKey = GetAxisKey(curveItemModels[i].Type);
                    lineSeries[i].Color = GetOxyColor(curveItemModels[i].ItemColor);
                    lineSeries[i].MarkerType = curveItemModels[i].MarkType;
                    lineSeries[i].MarkerStroke = GetOxyColor(curveItemModels[i].MarkStroke);
                    lineSeries[i].MarkerSize = curveItemModels[i].MarkSize;
                    viewModel?.PlotModel.Series.Add(lineSeries[i]);
                }
            } 
        }
        private List<ChartData> GetChartData()
        {
            var data=new List<ChartData>()
            {
                new ChartData{Date=DateTime.Now.Date.AddDays(-10),Data1=120,Data2=20},
                new ChartData{Date=DateTime.Now.Date.AddDays(-8),Data1=100,Data2=80},
                new ChartData{Date=DateTime.Now.Date.AddDays(-6),Data1=60,Data2=100},
                new ChartData{Date=DateTime.Now.Date.AddDays(-4),Data1=100,Data2=70},
                new ChartData{Date=DateTime.Now.Date.AddDays(-2),Data1=50,Data2=90}
            };
            return data;
        }
        private void LineSeriesDataSourceSet(List<ChartData> list)
        {
            for(int i=0;i<2;i++)
            {
                lineSeries[i].ItemsSource = list;
                lineSeries[i].DataFieldX = "Date";
                lineSeries[i].DataFieldY = "Data" + i;
                viewModel?.PlotModel.Series.Add(lineSeries[i]);
            }
        }
        /// <summary>
        /// 颜色转换
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        private OxyColor GetOxyColor(string color)
        {
            OxyColor oxyColor= OxyColors.Black;
            switch(color)
            {
                case "Black":
                    oxyColor = OxyColors.Black;
                    break;
                case "Red":
                    oxyColor = OxyColors.Red;
                    break;
                case "Blue":
                    oxyColor = OxyColors.Blue;
                    break;
                case "Green":
                    oxyColor = OxyColors.Green;
                    break;
                case "Yellow":
                    oxyColor = OxyColors.Yellow;
                    break;
                case "Violet":
                    oxyColor = OxyColors.Violet;
                    break;
            }
            return oxyColor;
        }
        /// <summary>
        /// Chart设置
        /// </summary>
        private void CreatePlot()
        {
            if (ChartSetStr == null) return;
            ChartSetModel ChartSet=JsonConvert.DeserializeObject<ChartSetModel>(ChartSetStr);
            //曲线设置
            viewModel = new CartesianChartViewModel();
            PlotView.DataContext = viewModel;
            viewModel.PlotModel.Title = ChartSet.Name;
            viewModel.PlotModel.Legends.Add(new Legend
            {
                LegendPlacement = LegendPlacement.Outside,
                LegendPosition = LegendPosition.BottomCenter,
                LegendOrientation = LegendOrientation.Horizontal,
                LegendBorderThickness = 0,
                LegendTextColor = OxyColors.LightGray
            });
            LinearAxisSet(ChartSet.AxisItemModels);
            LineSeriesSet(ChartSet.CurveItemModels);
            //LineSeriesDataSourceSet(GetChartData());
        }
    }
}

7、AxisItemModel.cs

namespace Accurate.Model
{
    /// <summary>
    /// 曲线设置类
    /// </summary>
    public class ChartSetModel
    {
        public string Name { get; set; } = "曲线示例";
        public ObservableCollection<AxisItemModel> AxisItemModels { get; set; }=new ObservableCollection<AxisItemModel>();
        public ObservableCollection<CurveItemModel> CurveItemModels { get; set; } = new ObservableCollection<CurveItemModel>();
    }
    /// <summary>
    /// 坐标轴设置
    /// </summary>
    public class AxisItemModel
    {
        public string Name { get; set; } = "X";
        public AxisType Type { get; set; } = 0;
        public AxisPosition Position { get; set; } = AxisPosition.Bottom;
        public double Minimum { get; set; } = 0;
        public double Step { get; set; } = 1;
        public double Maximum { get; set; } = 100;
    }
    /// <summary>
    /// 曲线设置
    /// </summary>
    public class CurveItemModel
    {
        public string Name { get; set; } = "时间";
        public AxisType Type { get; set; } = 0;
        public string ItemColor { get; set; } = "Black";
        public MarkerType MarkType { get; set; } = MarkerType.Circle;
        public string MarkStroke { get; set; } = "Black";
        public double MarkSize { get; set; } = 3;
    }
    /// <summary>
    /// 枚举轴类型
    /// </summary>
    public enum AxisType:int
    {
        X,Y,X1,Y1
    }
    /// <summary>
    /// 数据Item(单点数据添加)
    /// </summary>
    public class DataItem
    {
        public double DataX { get; set; }
        public List<double> DataYs { get; set; }=new List<double>();
    }
    public class ChartData
    {
        public DateTime Date { get; set; }
        public double Data1 { get; set; }
        public double Data2 { get; set; }
    }
}

8、MainWindowViewModel。cs

namespace Accurate.ViewModel
{
    public class MainWindowViewModel:NotifyBase
    {
		private string chartSetString;

		public string ChartSetString
		{
			get { return chartSetString; }
			set { chartSetString = value;this.DoNotify(); }
		}
        public ChartSetModel ChartSetData { get; set; } = new ChartSetModel();
        

        public MainWindowViewModel()
		{
            RefreshChartSet();
            
        }
		private void RefreshChartSet()
		{
            ChartSetData.Name = "正弦和余弦曲线";
            //设置坐标轴
            ChartSetData.AxisItemModels.Add(
                new AxisItemModel() { Name = "X", Type = AxisType.X, Position = OxyPlot.Axes.AxisPosition.Bottom, Minimum = 0, Step = 1, Maximum = 200 }
            );
            ChartSetData.AxisItemModels.Add(
                new AxisItemModel() { Name = "Y", Type = AxisType.Y, Position = OxyPlot.Axes.AxisPosition.Left, Minimum = -10, Step = 1, Maximum = 10 }
            );
            //设置曲线
            ChartSetData.CurveItemModels.Add(new CurveItemModel
            {
                Name = "正弦曲线",
                Type = AxisType.Y,
                ItemColor = "Red",
                MarkType = MarkerType.Circle,
                MarkStroke = "Blue",
                MarkSize = 3
            });
            ChartSetData.CurveItemModels.Add(new CurveItemModel
            {
                Name = "余弦曲线",
                Type = AxisType.Y,
                ItemColor = "Green",
                MarkType = MarkerType.Square,
                MarkStroke = "Yellow",
                MarkSize = 3
            });
            ChartSetString = JsonConvert.SerializeObject(ChartSetData);
        }

    }
}

9、MainWindow.xaml

<Window x:Class="Accurate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Accurate"
        xmlns:controls="clr-namespace:Accurate.Controls"
        mc:Ignorable="d"
        Title="MainWindow" Height="600" Width="800">
    <Grid>
        <controls:CartesianChart x:Name="Cartesian" ChartSetStr="{Binding ChartSetString}"  Height="450" Width="800" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

10、MainWindow.xaml.cs

namespace Accurate
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private DispatcherTimer? timer;
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainWindowViewModel();
            //this.Cartesian.lineSeries
            timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(100);
            timer.Tick += TimerTick;
            timer.Start();
        }
        double x = 0;
        /// <summary>
        /// 定时更新数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TimerTick(object? sender, EventArgs e)
        {
            double y = 10 * Math.Sin(x / 10.0);
            this.Cartesian.lineSeries[0]?.Points.Add(new DataPoint(x, y));
            double y1 = 10 * Math.Cos(x / 10.0);
            this.Cartesian.lineSeries[1]?.Points.Add(new DataPoint(x, y1));
            x++;
            if (this.Cartesian.lineSeries[0]?.Points.Count > 200)
            {
                this.Cartesian.lineSeries[0].Points.RemoveAt(0);
            }
            if (this.Cartesian.lineSeries[1]?.Points.Count > 200)
            {
                this.Cartesian.lineSeries[1].Points.RemoveAt(0);
            }
            this.Cartesian.viewModel?.PlotModel.InvalidatePlot(true);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/728361.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习】日常笔记10

loss_fn nn.MSELoss(reductionnone)这行代码&#xff0c;在这个上下文中&#xff0c;loss_fn实际上是一个损失函数对象而不是返回的具体值。 使用nn.MSELoss(reductionnone)创建的loss_fn是一个均方误差损失函数对象&#xff0c;而不是计算后的结果。要计算具体的损失值&…

(02)Cartographer源码无死角解析-(79) ROS服务→子图压缩与服务发送

讲解关于slam一系列文章汇总链接:史上最全slam从零开始&#xff0c;针对于本栏目讲解(02)Cartographer源码无死角解析-链接如下: (02)Cartographer源码无死角解析- (00)目录_最新无死角讲解&#xff1a;https://blog.csdn.net/weixin_43013761/article/details/127350885 文…

一篇文章带你吃透Go语言的Atomic和Channel--实战方法

一篇文章带你吃透Go语言的Atomic和Channel–实战方法 Atomic 要保证原子操作&#xff0c;一定要使用这几种方法 我们在学习 Mutex、RWMutex 等并发原语的实现时&#xff0c;你可以看到&#xff0c;最底层是通过 atomic 包中的一些原子操作来实现的 你可能会说&#xff0c;这些…

C语言中级篇请看另一篇文章,这一篇文章只写给高手看【高阶C语言】【更新中】【原创】

文章目录 前言define和typedef的区别?前言 关于C语言,博主已经写了不少的笔记总结了,C语言基础版可看我的专栏里面的C语言精华,C语言进阶版可看我的谭浩强C语言第五版,C语言高阶版看此篇文章即可 C Primer Plus书籍,C语言精华,截图 + 代码 + 学习总结笔记【11000字】【…

AOCVSBOCV、AOCV table

文章目录 AOCV&#xff08;Advanced OCV&#xff09;&SBOCV&#xff08;Stage Based OCV&#xff09;---更精确&#xff0c;剔除悲观度Random variation&#xff08;Depth/Stage based AOCV&#xff09;Systematic variation&#xff08;Distance based AOCV&#xff09;一…

阻塞队列是什么

1、阻塞队列是什么? (1) 栈与队列 1&#xff09;栈&#xff1a;先进后出&#xff0c;后进先出 2&#xff09;队列&#xff1a;先进先出 (2) 阻塞队列 阻塞&#xff1a;必须要阻塞/不得不阻塞 阻塞队列是一个队列&#xff0c;在数据结构中起的作用如下图&#xff1a; 线程1…

直播美颜工具与实时美颜SDK开发指南

近年来&#xff0c;随着直播行业的蓬勃发展&#xff0c;越来越多的用户开始关注直播内容的质量。其中&#xff0c;美颜功能成为直播平台上不可或缺的一项特色功能。下文小编将从基础原理到实际应用&#xff0c;帮助开发者更好地实现高效又自然的美颜效果。 一、背景 在直播过…

spring之ApplicationContext

spring之ApplicationContext ApplicationContextApplicationContext源码ApplicationContext继承接口分析ApplicationContext两个比较重要的实现类AnnotationConfigApplicationContextClassPathXmlApplicationContext 国际化---MessageSource资源加载---ResourceLoader获取运行时…

多元回归预测 | Matlab鲸鱼算法(WOA)优化极限梯度提升树XGBoost回归预测,WOA-XGBoost回归预测模型,多变量输入模型

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 多元回归预测 | Matlab鲸鱼算法(WOA)优化极限梯度提升树XGBoost回归预测,WOA-XGBoost回归预测模型,多变量输入模型 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源…

css实现九宫格有边框,最外层四周无边框

1.先设置9个div&#xff0c;如下&#xff1a; <div class"wrapper"><div class"cell"></div><div class"cell"></div><div class"cell"></div><div class"cell"></div&…

【MySQL】连接 MySQL使用二进制方式连接和脚本连接,修改密码,增加新用户,显示命令

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…

RocketMQ5.0--消息发送

RocketMQ5.0–消息发送 一、消息 // 消息所属topic private String topic; // 消息Flag&#xff08;RocketMQ不作处理&#xff09;&#xff0c;即&#xff1a;用户处理 private int flag; // 扩展属性 private Map<String, String> properties; // 消息体 private byte…

Pandas+Pyecharts | 北京近五年历史天气数据可视化

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 处理最低气温最高气温数据2.3 处理日期数据2.4 处理风力风向数据 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 2018-2022年历史温度分布…

漏洞复现 || H3C iMC 存在远程命令执行

免责声明 技术文章仅供参考,任何个人和组织使用网络应当遵守宪法法律,遵守公共秩序,尊重社会公德,不得利用网络从事危害国家安全、荣誉和利益,未经授权请勿利用文章中的技术资料对任何计算机系统进行入侵操作。利用此文所提供的信息而造成的直接或间接后果和损失,均由使…

软件的验收测试应该怎么正确实施?

验收测试的主要目的是为了确定软件系统是否满足客户或最终用户的需求和期望&#xff0c;同时确保软件产品的质量标准达到预期。验收测试还可以提供客户和最终用户关于软件系统质量的反馈和建议&#xff0c;以便软件开发团队能够更好地改进和优化软件产品&#xff0c;那软件的验…

【QT】QtXlsx安装使用

QtXlsx库 QtXlsx介绍QtXlsx Qt配置简单使用示例 QtXlsx介绍 QtXlsx是一个可以读取和写入Excel文件的库。它不需要Microsoft Excel&#xff0c;可以在Qt5支持的任何平台上使用。 这里一定是需要QT5支持的。 生成一个新的 .xlsx 文件从现有的 .xlsx 文件中提取数据编辑现有的 .x…

Linux常用指令(下)

目录 一&#xff1a;Linux基础指令 查看联机手册 文本查看相关 时间相关 查找相关 打包和压缩相关 查看Linux版本和体系 其它指令和热键 二&#xff1a;重定向 输入重定向 输出重定向 三&#xff1a;管道 一&#xff1a;Linux基础指令 查看联机手册 Linux的命令有…

ADS笔记,新旧两组仿真数据进行绘图和列表对比

做个笔记&#xff0c;以防遗忘 ADS版本&#xff1a;2023 原理图器件参数的不同&#xff0c;怎么进行对比观看&#xff0c;操作如下 目录 一、数据绘图对比二、数据列表对比 一、数据绘图对比 选择Simulation Setting 然后修改原理图器件的参数&#xff0c;再次重复之前的操作…

SpringBoot2+Vue2实战(十三)用户前台页面设计与实现

Front.vue <template><div><!--头部--><div style"display: flex; height: 60px;line-height: 60px;border-bottom: 1px solid #ccc"><div style"width: 300px;display: flex;padding-left: 30px"><div style"widt…

CENTOS上的网络安全工具(二十七)SPARK+NetSA Security Tools容器化部署(3)

上回说到在我们搭好的YAF3环境上使用yaf处理pcap文件得到silk flow&#xff0c;再使用super mediator工具转为ipfix&#xff0c;继而在spark中导入mothra&#xff0c;就可以开始数据分析了。然而在我们粗粗一用之下&#xff0c;却发现DPI信息在ipfix文件中找不到&#xff0c;到…