2024年4月

如何合理使用动效来获得更好的性能

  1. 组件转场动画使用 transition


    • 推荐使用转场动画(transition)而不是组件动画(animateTo),因为 transition 只需要在条件改变时更新一次,而 animateTo 需要在动画前后做两次属性更新,导致性能开销更大。
    • 反例:通过改变透明度属性并使用 animateTo 来隐藏和显示组件。
    • 正例:直接使用 transition 动画,通过改变透明度实现组件的出现与消失。
  1. 组件布局改动时使用图形变换属性动画


    • 当需要改动组件的布局显示时,推荐使用图形变换属性(如平移、旋转、缩放)而不是改动布局属性(如 width、height、layoutWeight),因为图形变换不会重新触发布局,从而减少性能开销。
    • 反例:通过设置布局属性 width 和 height 来改变组件大小。
    • 正例:通过设置图形变换属性 scale 来改变组件大小。
  1. 动画参数相同时使用同一个 animateTo


    • 如果多个属性需要使用相同的动画参数进行动画处理,应该将它们合并到一个 animateTo 闭包中,以减少组件更新的次数。
    • 反例:将相同动画参数的状态变量更新放在不同的动画闭包中。
    • 正例:将相同动画参数的动画合并在一个动画闭包中。
  1. 多次 animateTo 时统一更新状态变量


    • 在执行多个 animateTo 之前,应该统一更新状态变量,避免在执行动画之间产生冗余的状态更新。
    • 反例:在两个 animateTo 之间更新状态变量。
    • 正例 1:在 animateTo 之前使用原始状态,让动画从原始状态过渡到指定状态。
    • 正例 2:在 animateTo 之前显式指定所有需要动画的属性初值,统一更新到节点中,然后再执行动画。

应用性能提升

1. 使用数据懒加载

在处理长列表数据时,传统的循环渲染方式会一次性加载所有列表元素,这会导致页面启动时间过长,影响用户体验,并增加服务器压力。为了解决这个问题,推荐使用 DataSource 来实现数据懒加载技术。通过懒加载,只有当数据进入可视区域时才加载和渲染,这样可以显著提高页面的响应速度和性能。

2. 设置 List 组件的宽高

在使用 Scroll 容器组件嵌套 List 组件加载长列表时,如果没有指定 List 的宽高尺寸,List 将会布局其所有子组件,这会导致性能问题。通过设置 List 的宽高,可以确保只布局 List 显示区域内的子组件,从而提高性能。
Scroll 嵌套 List 时:
  • List 没有设置宽高,会布局 List 的所有子组件。
  • List 设置宽高,会布局 List 显示区域内的子组件。
  • List 使用
    ForEach
    加载子组件时,无论是否设置 List 的宽高,都会加载所有子组件。
  • List 使用
    LazyForEach
    加载子组件时,没有设置 List 的宽高,会加载所有子组件,设置了 List 的宽高,会加载 List 显示区域内的子组件。

3. 使用条件渲染替代显隐控制

使用 visibility 属性控制组件的显隐状态时,即使组件不可见,它仍然会被重新创建,这会造成性能损耗。通过使用 if 条件渲染,可以避免组件的重新创建过程,从而提升性能。

4. 使用 Column/Row 替代 Flex

Flex 容器组件在默认情况下存在 shrink 属性,这可能导致二次布局,影响页面渲染性能。通过使用 Column 和 Row 组件替代 Flex,可以避免二次布局带来的性能问题。

5. 减少应用滑动白块

在应用中,滑动白块是一个常见的性能问题。通过增大 List/Grid 控件的 cachedCount 参数,可以预加载更多的 item,减少白块的出现。同时,如果需要请求网络图片,可以提前下载内容,以减少滑动时的白块现象。

状态管理优化

以下是文档中提到的一些关键点:
  1. 使用@ObjectLink 代替@Prop 减少不必要的深拷贝
在父子组件间传递数值时,如果子组件不需要改变状态变量的值,使用@ObjectLink 比@Prop 更优,因为@Prop 会导致深拷贝,增加性能开销。
  1. 不使用状态变量强行更新非状态变量关联组件
    :开发者应避免通过改变自定义的 UI 状态变量来带动常规变量的更新,而应将相关成员变量用@State 装饰,以便框架能够检测状态变化并触发 UI 更新。
  1. 精准控制状态变量关联的组件数
    :建议每个状态变量关联的组件数少于 20 个,以减少不必要的组件刷新,提高效率。
  1. 合理控制对象类型状态变量关联的组件数量
    :如果一个复杂对象被定义为状态变量,需要合理控制其关联的组件数,避免“冗余刷新”。
  1. 查询状态变量关联的组件数
    :可以使用 HiDumper 工具查看状态变量关联的组件数,进行性能优化。
  1. 避免在 for、while 等循环逻辑中频繁读取状态变量
    :应该在循环外面读取状态变量,避免在循环逻辑中频繁读取,以提高性能。

避免冗余操作

  1. 避免在高频回调中进行冗余操作
    :在处理如滚动事件、触摸事件等高频回调时,应避免在回调函数内部执行冗余的日志记录、Trace追踪和耗时操作。这些操作会严重影响应用的性能和响应速度。
  1. 删除冗余Trace和日志打印
    :在开发阶段,日志和Trace追踪是重要的辅助工具,但在发布版本中应移除这些冗余的输出,以避免不必要的性能开销。
  1. 避免设置冗余的系统回调监听
    :如果回调函数体内不包含任何业务逻辑代码,应将其删除。注册但未使用的回调会消耗系统资源,影响程序运行效率。

一、前言

在项目开发过程中,DataGrid是经常使用到的一个数据展示控件,而通常表格的最后一列是作为操作列存在,比如会有编辑、删除等功能按钮。但WPF的原始DataGrid中,默认只支持固定左侧列,这跟大家习惯性操作列放最后不符,今天就来介绍一种简单的方式实现固定右侧列。(这里的实现方式参考的大佬的两个DataGrid合并在一起的方式,原博客:
https://www.cnblogs.com/akwkevin/p/17872348.html

二、正文

1、上面大佬的实现,就直接基于他自己的控件库里实现的,这里我介绍的方式是如何引用了别的第三方库的情况下,在项目代码中再实现自定义可以固定右侧列的DataGrid控件;

2、首先新建个项目,项目里引用了HandyControl控件库和微软的mvvm库。

3、给项目添加一个自定义控件,记得不是自定义用户控件,这里命名为MyDataGrid,然后就可以从上面大佬那里搬代码过来,关键就是添加RightFrozenCount这个依赖属性代码和两个DataGrid之间的滚动同步代码

public intRightFrozenCount
{
get { return (int)GetValue(RightFrozenCountProperty); }set{ SetValue(RightFrozenCountProperty, value); }
}
public static readonly DependencyProperty RightFrozenCountProperty =DependencyProperty.Register(nameof(RightFrozenCount),typeof(int), typeof(MyDataGrid),new PropertyMetadata(0, OnRightFrozenCountChanged));private static voidOnRightFrozenCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d isMyDataGrid dataGridRightFrozen)
{
dataGridRightFrozen.OnRightFrozenCountChanged();
}
}
private voidOnRightFrozenCountChanged()
{
if (_rightDataGrid != null)
{
if (RightFrozenCount > 0)
{
for (int i = 0; i < _rightDataGrid.Columns.Count; i++)
{
var column =_rightDataGrid.Columns[i];
_rightDataGrid.Columns.Remove(column);
Columns.Add(column);
}
for (int i = 0; i < RightFrozenCount; i++)
{
var last = Columns[^1];
Columns.Remove(last);

_rightDataGrid.Columns.Insert(
0, last);
}
_rightDataGrid.SetCurrentValue(VisibilityProperty, Visibility.Visible);
}
else{
_rightDataGrid.SetCurrentValue(VisibilityProperty, Visibility.Collapsed);
}
}
}
public override voidOnApplyTemplate()
{
base.OnApplyTemplate();if (_scrollViewer != null)
{
_scrollViewer.ScrollChanged
-=ScrollViewer_ScrollChanged;
}
if (_rightScrollViewer != null)
{
_rightScrollViewer.ScrollChanged
-=RightScrollViewer_ScrollChanged;
}
if (_rightDataGrid != null)
{
_rightDataGrid.ScrollViewerChanged
-=ScrollViewerChanged;
_rightDataGrid.SelectionChanged
-=RightDataGrid_SelectionChanged;
}

_scrollViewer
= GetTemplateChild(DG_ScrollViewer) asScrollViewer;if (_scrollViewer != null)
{
_scrollViewer.ScrollChanged
+=ScrollViewer_ScrollChanged;
}

_rightDataGrid
= GetTemplateChild(PART_Right) asDataGridScrollView;if (_rightDataGrid != null)
{
_rightDataGrid.ScrollViewerChanged
+=ScrollViewerChanged;
_rightDataGrid.SelectionChanged
+=RightDataGrid_SelectionChanged;
}
SelectionChanged
+=DataGridRightFrozen_SelectionChanged;
}
private voidScrollViewerChanged(ScrollViewer viewer)
{
_rightScrollViewer
=viewer;
_rightScrollViewer.ScrollChanged
+=RightScrollViewer_ScrollChanged;
}
private void ScrollViewer_ScrollChanged(objectsender, ScrollChangedEventArgs e)
{
_rightScrollViewer
?.ScrollToVerticalOffset(_scrollViewer.VerticalOffset);
}
private void RightScrollViewer_ScrollChanged(objectsender, ScrollChangedEventArgs e)
{
_scrollViewer
?.ScrollToVerticalOffset(_rightScrollViewer.VerticalOffset);
}
private void RightDataGrid_SelectionChanged(objectsender, SelectionChangedEventArgs e)
{
SetCurrentValue(SelectedItemProperty, _rightDataGrid.SelectedItem);
}
private void DataGridRightFrozen_SelectionChanged(objectsender, SelectionChangedEventArgs e)
{
_rightDataGrid.SetCurrentValue(SelectedItemProperty, SelectedItem);
}

4、接着去到HandyControl的开源库那里,找到DataGrid的样式,然后复制到项目中

5、然后对原来的Style进行修改,对ControlTemplate的布局添加上作为固定列的DataGrid

6、至此,自定义支持右侧列固定的DataGrid就完成了,效果如下:

7、代码地址:
https://gitee.com/liulang_g/data-grid-demo

iNeuOS工业互联网操作系统,民爆远程运维平台案例

目       录

1.      概述... 2

2.      iNeuOS在
民爆生产厂区和北京运维中心配置... 3

1.1           生产厂区配置... 3

1.2           运维中心配置... 7


1.   概述

针对本项目进行初步调研,项目的总体需求为满足新建厂区的信息化建设,实现在线数据实时监测、预警、分析和MES业务系统。

针对民爆行业信息化建设方面,领导决策层、业务人员、技术人员迫切转变发展思路和思维模式,充分利用物联网、大数据、人工智能、数字孪生、工业互联网等先进理念和技术,提升工业企业的数字化、网络化、智能化、标准化水平。以数据为中心、以生产过程为核心、以工具赋能构建业务功能,实现设备状态监测及预警、生产过程优化、科学智能决策、降低能源消耗等业务,确保提升信息化水平的同时,保障项目具体落地。

信息化建设以企业追求效益为主导,信息化要为企业的生存服务,提供先进技术和优化生产过程管理相结合。但是,信息化达到企业的发展要求需要一个发展过程,所以信息化需要与企业当前的发展水平相匹配。用户方与信息化承建方密切配合,达到理想的目标和效果。

民爆生产厂区有地面站和
民爆车,现场地面站的控制系统为西门子PLC和欧姆龙PLC,民爆车为三菱PLC,地面站通过光纤与本地机房进行数据交互,
民爆车的位置及其他数据通过4G与本地机房进行数据交互。本地机房与北京运维中心进行数据交互,实现民爆行业的综合运维平台。
民爆生产厂区和北京运维中心均采用iNeuOS工业互联网平台操作系统作为基础平台进行MES业务扩展,MES主要功能包括:生产计划、生产流程、设备管理、库存管理、人员管理等。最终用户通过电脑浏览器和手机APP进行应用。技术框架示意,如下图:

2.   iNeuOS在生产厂区和北京运维中心配置

iNeuOS在
民爆生产厂区(V4.1版本)和北京运维中心(V5.2版本)进行两个层级部署,实现异构网络和数据互联互通,保障数据交互的实时性、完整性、唯一性和安全性。

1.1    生产厂区配置

新建设备模型,现场采集的是欧姆龙PLC数据,选择FinsNet(TCP),如果是其他设备,那么请选择相应的驱动。如下图:

选择【Socket】选项卡,填写PLC的IP地址、端口Port和工作模型(TcpClient),如下图:

在【数据点】选项卡中增加、编辑和删除数据点信息,如下图:

新增加一个数据点,设置从机地址、寄存器地址,例如读取一个开关量,在寄存器地址配置:CIO253.06。如下图:

读取上来数据之后,在桌面【数据转发】功能中把数据转发到北京运维中心,填写站点编号、任务名称、远程IP、远程端口和转发周期,站点编号与“1.2运维中心配置”设备信息的【
设备地址】
和【
设备编码】
相对应,远程端口与“1.2运维中心配置”中服务实例的侦听端口相对应。如下图:

选择要转发到北京运维中心的数据点。如下图:

配置好之后重新启动后台服务,数据实时采集和转发,如下图:

1.2    运维中心配置

新建设备模型,配置设备地址、设备编码和设备驱动,设备地址和设备编码与“1.1 生产厂区配置”中数据转发中【站点编号】相对应,设备驱动选择:iNeuLink(网关)。如下图:

服务实例中心配置数据分发(DeviceCode)、控制模型(Self)和设备驱动启用检测数据包,检测数据包主要是保障数据传输的稳定性和完整性。如下图:

民爆生产厂区的数据点会自动同步到北京运维中心,不需要在运维中心重新配置数据点。如下图:

实时接收数据,如下图:


物联网&大数据技术 QQ群:54256083

物联网&大数据项目 QQ群:727664080

QQ:504547114

微信:wxzz0151

博客:https://www.cnblogs.com/lsjwq

微信公众号:iNeuOS

本文介绍基于
ArcMap
软件,绘制论文中
研究区域示意图

概况图
等的方法。

最近需要绘制与地学有关论文、文献中的
研究区域概况图
。对于这一类图片,我个人比较喜欢基于
ArcMap

PPT
结合的方式来绘制,具体操作如下。

当然,首先这里要提一句:大家一定需要注意,绘制我国相关的地图时(尤其是论文中我国的地图),一定注意
南海诸岛、十段线、藏南、阿克赛钦
等细节部分。

先来看看成果图:

image

话不多说,开始绘制,首先我们先做副图。在
ArcMap
中导入全国矢量图层(包括南海诸岛);随后,修改地图符号系统,并导入十段线。

接下来,导入本文研究区域,同时修改符号系统。

完成后,我们切换到“
Layout View
”这一视图,调整好范围和大小,用如下方法导出地图即可。因为是副图,暂时不需要调整地图要素、地图边框等内容。

设置输出属性。

随后,新建一个
PPT
文件,并将上述新生成的图片导入到
PPT
中。

如果
PPT
中图片不清楚,可以按照如下方式设置一下
PPT
文件内图片的压缩选项。

接下来,我们进行主图的绘制。导入研究区域与水体等相关图层,并配置符号系统。

导入指北针、比例尺、图例等。

我的比例尺属性设置情况如下。

接下来,我们需要设置图片边框上的格网。在研究区域图层上右键,选择
属性

选择“
New Grid
”。

我们选择第一个即可。

这里先大概设置一个间隔就好,反正后期可以调整。

完成后我们可以看到,图片边框格网有点密集,不美观。

我们就在属性界面,选择“
Properties
”。

选择“
Intervals
”,配置合适的经纬度间隔即可。

此时可以看到,间隔已经修改完毕,但是字号很小。

在以下界面可以修改字体、字号。

然后在以下界面,修改经纬度格网符号出现的区域;因为不用一幅图的四个边框都带着经纬度,会显得比较臃肿,选择其中的两条边即可。

为了美观,将格网伸出的那一条线朝向图片内部。

随后,由于我的研究区域比较大,经纬度的度数变化很大,没有必要再看分、秒的数据,因此直接选择不显示为
0
的分、秒数据。

此外,添加图例时,可以直接在图层属性中修改图例框中该图层所显示的内容。

最终成图如下:

然后将其导出即可。主图的
dpi
可以设置稍微大一点,分辨率高一些。然后将新生成的图同样导入到
PPT
中。

随后,我们用箭头来显示主图与副图的关系。

如下所示。

我们还可以用矩形工具来在副图中框选研究区域,显得更加直观。

最后,将
PPT
中全部内容全选并组合,后期导出或复制成为图片格式即可。

上次发布了托盘窗体的显示与隐藏的博文:,但是在测试窗体最大化的时候发现窗体没有隐藏,调试了下知道是窗体是否被遮挡这个函数的判断有问题。于是就研究了该代码,然后联系了该操作类的作者,也是博客园的园友,然后在他的帮助下将操作类进行了更新,添加了特殊窗体的处理代码,这才使得该操作类得到了完善。

这个例子主要就是介绍这个窗体是否被遮挡的操作类的使用。

1、
项目目录;

2、
源码介绍;

1) 操作类介绍;

代码挺简单,就是自调用,判断窗体是否在某个矩形区域内。

2) 主窗体使用介绍;

代码为点击托盘图标,对窗体进行显示和隐藏操作。

3、
运行界面;

因为界面为一个默认的窗体,所以这里就不提供截图了。

4、
使用介绍;

1) 操作类使用;

2) 主窗体使用;

5、
源码下载;

这里提供源码下载:
https://download.csdn.net/download/lzhdim/89103167

6、
其它建议;

此例子代码已经非常简单明了,就是如果窗体需要最大化操作的,才需要调试该应用,找出窗体最大化时候被遮挡的窗体坐标,修改到操作类的特殊窗体坐标里才行。

上面介绍了窗体是否被遮挡的操作类的使用方法,请需要的读者自己复用该代码,根据自己的需要进行修改使用即可。