Skip to content

LoHhhha/performance-monitor-winui3

Repository files navigation

效率工具箱文档

效率工具箱是由LoHhhha开发的一款基于Windows SDK 1.5(WinUI3)开发的软件。旨在实现一些极客功能如:计算机性能监测、网络IP地址查看、TODO列表、日程表等功能,同时集成Dell G15系列AWCC-WMI相关接口,实现风扇转速调整、性能模式切换的功能。

注:文档给出的前端设置均为简化版,未指定任何参数,仅做参考,具体请参见对应源代码。

主要特性

WinUI设计规范

多类交互

再次确认

多语言支持

Toast

目前使用Toast提示的行为

  • Overclock页面切换模式
  • 程序异常退出

模块

性能监视器模块

性能页面Monitor

实现的功能

  • 实时显示设备工作情况
  • 显示的项目完全自定义

依赖工具

  • Performance目录

前端设置

<ScrollView>
    <Grid x:Name="DisplayGrid">
    </Grid>
</ScrollView>

实现方法

  • 全部元素动态生成,使用performance_monitor_winui3.Tools.Utils类中的工具完成对控件的动态生成,添加到DisplayGrid
    • 为什么要动态生成?由于本页中的所有子模块都可以随意组合、随意移动位置,故本页所有显示控件都是动态生成的。
    • 方法包括使用到的方法有AddTitle2GridAddPairGrid2GridAddPairWithProgressBarGrid2GridAddLoadingProgressBar2Grid,用于生成对应的子项。
    • 使用文字-数值对、文字-进度条-文字对、文字标题表示各子项。
  • 使用Information.TotalInformation完成对设备信息的收集。
  • 在对应ViewModel中使用_selectedTypes来确定显示的项目。
  • 使用Microsoft.UI.Xaml.DispatcherTimertimer来在每一个需要更新的时刻更新DisplayGrid
  • 使用System.Threading.SemaphoretimerNotRunning来确保timer产生的任务只有一个能对Information.TotalInformation进行操控。
  • 使用异步优化界面,尽量不阻塞UI线程。
  • 当从页面退出时,也就是调用OnNavigatedFrom时停止timer
  • 当回到页面时,也就是调用OnNavigatedTo时继续timer

页面展示

  • 多种性能指标随意组合,完全自定义
  • 刷新时间间隔自由定义

网络页面Network

实现的功能

  • 显示各网卡工作情况,包括IP地址、DHCP服务器等

依赖工具

  • Performance目录

前端设置

<ScrollView>
    <Grid x:Name="DisplayGrid">
    </Grid>
</ScrollView>

实现方法

  • 全部元素动态生成,使用performance_monitor_winui3.Tools.Utils类中的工具完成对控件的动态生成,添加到DisplayGrid
  • 使用Microsoft.UI.Xaml.DispatcherTimertimer来在每一个需要更新的时刻更新DisplayGrid
  • 使用System.Threading.SemaphoretimerNotRunning来确保timer产生的任务只有一个能对Information.TotalInformation进行操控。
  • 使用异步优化界面,尽量不阻塞UI线程。
  • 当从页面退出时,也就是调用OnNavigatedFrom时停止timer
  • 当回到页面时,也就是调用OnNavigatedTo时继续timer

页面展示

超载页面Overclock

实现的功能

  • 实时显示设备CPUGPU温度,CPUGPU对应风扇温度
  • 实现风扇转速调节、性能模式切换。
  • 注:仅Dell G15系列可用。

依赖工具

  • AWCC目录

前端设置

<Grid>
    <ScrollView>
        <StackPanel>
            <InfoBar Name="ErrorInfoBar"/>
            <Grid>
                <TextBlock/>
                <tc:RadialGauge/>
                <tc:RadialGauge/>
                <TextBlock/>
                <TextBlock/>
            </Grid>

            <Grid>
                <TextBlock/>
                <tc:RadialGauge/>
                <tc:RadialGauge/>
                <TextBlock/>
                <TextBlock/>
            </Grid>


            <Grid>
                <TextBlock/>
                <ComboBox>
                    <ComboBoxItem/>
                    <ComboBoxItem/>
                    <ComboBoxItem/>
                </ComboBox>
            </Grid>

            <Grid Name="SliderGrid" Visibility="Collapsed">
                <TextBlock/>
                <TextBlock/>
                <Slider/>
                <TextBlock/>
                <Slider/>
            </Grid>
        </StackPanel>
    </ScrollView>
</Grid>

实现方法

  • 首先调用AWCCWMI类方法,确认是否存在AWCCWmiMethodFunction的WMI服务,如果不存在,将错误信息打印在ErrorInfoBar
  • AWCCWMI类方法获取具体的信息,更新到对应的控件。
  • 使用Microsoft.UI.Xaml.DispatcherTimertimer来在每一个需要更新的时刻更新DisplayGrid
  • 使用System.Threading.SemaphoretimerNotRunning来确保timer产生的任务只有一个能对Information.TotalInformation进行操控。
  • 使用异步优化界面,尽量不阻塞UI线程。
  • 当从页面退出时,也就是调用OnNavigatedFrom时停止timer
  • 当回到页面时,也就是调用OnNavigatedTo时继续timer

页面展示

  • 在选择用户模式时会将滑动条显示并允许调节。

实用工具模块

待办页面ToDoList

实现的功能

  • 待办事项的查看、增加、删除、修改、改变位置、完成标记。
  • 已办事项的查看、删除。

前端设置

<Grid>
    <ScrollView>
        <StackPanel>
            <TextBlock>
                <Run/>
            </TextBlock>
            <ListView ItemsSource="{x:Bind ViewModel.ToDoListItems}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="models:ToDoListItem">
                        <Border>
                            <Border.ContextFlyout>
                                <MenuFlyout>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutSeparator/>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutItem/>
                            </Border.ContextFlyout>
                            <Grid>
                                <TextBlock/>
                                <TextBlock/>
                                <TextBlock/>
                            </Grid>
                        </Border>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            <TextBlock>
                <Run/>
            </TextBlock>
            <ListView ItemsSource="{x:Bind ViewModel.FinishListItems}">
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="models:FinishListItem">
                        <Border>
                            <Border.ContextFlyout>
                                <MenuFlyout>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutSeparator/>
                                    <MenuFlyoutItem/>
                                </MenuFlyout>
                            </Border.ContextFlyout>
                            <Grid Margin="10">
                                <TextBlock/>
                                <TextBlock/>
                                <TextBlock/>
                                <TextBlock/>
                                <TextBlock/>
                            </Grid>
                        </Border>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackPanel>
    </ScrollView>
    <Button/>
</Grid>

实现方法

  • MVVM模式开发。
    • 持久化封装为ToDoListDao类,负责控制与嵌入式数据库LiteDB交互。
    • ObservableCollection<T>类型的ToDoListItemsFinishListItems存在于ViewModel当中,在对其操作的同时,使用ToDoListDao同步完成持久化(数据量不大,所以使用同步操作)。
    • 前端使用绑定模式显示。
  • 针对每个行为绑定一个委托,完成对列表元素的操作。
  • ToDoListItems用于记录添加过的待办。
  • FinishListItems用于记录已经完成的事情。
  • 使用动态生成的ContentDialog完成对操作的可视化。

页面展示

  • 单击对应的项目可以查看详细项目情况,光标滑到对应项目项目边框加粗。

  • 右击项目显示更多对项目的操作。

  • 添加、修改操作有对应的值校验。

日程页面Schedule

实现的功能

  • 日程的添加
    • 可选择星期或是每天需要完成
    • 日程的名称
    • 日程的备注
    • 需要完成的时间段
  • 日程自动按开始时间排序。
  • 在顶部可选择感兴趣的星期需要,下方列表显示对应的工作。
  • 首次打开默认显示当天对应的星期选项。

前端设置

<Grid>
	<tc:Segmented>
		<tc:SegmentedItem Content="Mon"/>
		<tc:SegmentedItem Content="Tue"/>
		<tc:SegmentedItem Content="Wed"/>
		<tc:SegmentedItem Content="Thu"/>
		<tc:SegmentedItem Content="Fri"/>
        <tc:SegmentedItem Content="Sat"/>
        <tc:SegmentedItem Content="Sun"/>
    </tc:Segmented>
	<ScrollView>
        <StackPanel>
            <ProgressRing/>
			<ListView ItemsSource="{x:Bind ViewItems}">
				<ListView.ItemTemplate>
					<DataTemplate x:DataType="models:ScheduleItem">
						<Border>
							<Border.ContextFlyout>
								<MenuFlyout>
									<MenuFlyoutItem/>
									<MenuFlyoutSeparator/>
									<MenuFlyoutItem/>
									<MenuFlyoutItem/>
								</MenuFlyout>
							</Border.ContextFlyout>
							<Grid>
								<TextBlock/>
								<TextBlock/>
                                <TextBlock/>
								<TextBlock/>
							</Grid>
						</Border>
					</DataTemplate>
				</ListView.ItemTemplate>
			</ListView>
        </StackPanel>
    </ScrollView>
	<Button/>
</Grid>

实现方法

  • MVVM模式开发。
    • 持久化封装为ScheduleDao类,负责控制与嵌入式数据库LiteDB交互。
    • ObservableCollection<T>类型的ViewItems,在对其操作的同时,使用ScheduleDao同步完成持久化。
    • 前端使用绑定模式显示。
  • ViewItems用于记录当前选择下应该显示的日程。
  • 使用动态生成的ContentDialog完成对操作的可视化。

页面展示

  • 根据当前时间自动选择对应的星期,并显示对应的日程。

  • 添加值校验、日程可选择每天。

事务页面Access

实现的功能

  • 事务自定义
    • 指定事务名称
    • 指定事务执行的CMD命令,可多行
    • 指定执行时是否保留窗口显示
    • 指定执行完毕后是否关闭窗口
  • 事务的查看、增加、删除、修改、改变位置、执行。

前端设置

<Grid>
	<ScrollView>
		<StackPanel>
			<ListView ItemsSource="{x:Bind ViewModel.ErrorMessages}">
				<ListView.ItemTemplate>
					<DataTemplate x:DataType="models:AccessRunError">
						<InfoBar/>
					</DataTemplate>
				</ListView.ItemTemplate>
			</ListView>
			
			<ListView ItemsSource="{x:Bind ViewModel.AccessItems}">
				<ListView.ItemTemplate>
					<DataTemplate x:DataType="models:AccessItem">
						<Border>
							<Border.ContextFlyout>
								<MenuFlyout>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutSeparator/>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutItem/>
                                    <MenuFlyoutItem/>
								</MenuFlyout>
							</Border.ContextFlyout>
							<Grid>
								<TextBlock/>
                                <Button/>
							</Grid>
						</Border>
					</DataTemplate>
				</ListView.ItemTemplate>
			</ListView>
		</StackPanel>
	</ScrollView>
	<Button/>
</Grid>

实现方法

  • MVVM模式开发。
    • 持久化封装为AccessDao类,负责控制与嵌入式数据库LiteDB交互。
    • ObservableCollection<T>类型的ErrorMessagesAccessItems存在于ViewModel当中,在对其操作的同时,使用AccessDao同步完成持久化(数据量不大,所以使用同步操作,ErrorMessages不做持久化)。
    • 前端使用绑定模式显示。
  • ErrorMessages用于记录之前执行的任务出现的错误。
  • AccessItems用于记录添加过的事务。
  • 使用动态生成的ContentDialog完成对操作的可视化。

页面展示

  • 光标滑到对应项目项目边框加粗。

  • 单击对应的项目可以查看详细项目情况,同样可以右键显示更多,此处不展示。添加时对多选项进行了约束如果不显示窗口则一定要完成后退出。

  • 出错队列。

设置页面Setting

实现的功能

  • 个性化设置
    • 显示模式:深色、浅色、跟随系统
    • 性能页面Monitor展示的元素
    • 性能页面Monitor、网络页面Network刷新的时间间隔。
  • 全球化
    • 语言设置
      • CN-ZH
      • EN-US

前端设置

<ScrollView VerticalScrollBarVisibility="Hidden">
    <StackPanel>
        <TextBlock/>
        <StackPanel>
            <!--ThemeSetting-->
            <controls:SettingsCard>
                <ComboBox>
                    <ComboBoxItem/>
                    <ComboBoxItem/>
                    <ComboBoxItem/>
                </ComboBox>
            </controls:SettingsCard>
            <!--ThemeSetting-->

            <!--MonitorOrderSetting-->
            <controls:SettingsExpander>
                <controls:SettingsExpander.ItemsHeader>
                    <ListView ItemsSource="{x:Bind ViewModel.MonitorItems}">
                        <ListView.ItemTemplate>
                            <DataTemplate x:DataType="models:MonitorOrderListItem">
                                <TextBlock/>
                                <StackPanel/>
                                    <Button/>
                                    <Button/>
                                    <Button/>
                                </StackPanel>
                                </Grid>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </controls:SettingsExpander.ItemsHeader>
                <controls:SettingsExpander.ItemsFooter>
                    <Grid>
                        <Button/>
                        <Button/>
                        <Button/>
                    </Grid>
                </controls:SettingsExpander.ItemsFooter>
            </controls:SettingsExpander>
            <!--MonitorOrderSetting-->

            <!--TimerSetting-->
            <controls:SettingsExpander>
                <controls:SettingsExpander.Items>
                    <controls:SettingsCard>
                        <StackPanel>
                            <NumberBox/>
                            <TextBlock/>
                        </StackPanel>
                    </controls:SettingsCard>
                    <controls:SettingsCard>
                        <StackPanel>
                            <NumberBox/>
                            <TextBlock/>
                        </StackPanel>
                    </controls:SettingsCard>
                </controls:SettingsExpander.Items>
            </controls:SettingsExpander>
            <!--TimerSetting-->
        </StackPanel>

        <TextBlock/>
        <controls:SettingsCard>
            <ComboBox>
                <x:String>en-us</x:String>
                <x:String>zh-cn</x:String>
            </ComboBox>
        </controls:SettingsCard>

        <TextBlock/>
        <controls:SettingsExpander>
            <controls:SettingsExpander.Items>
                <controls:SettingsCard>
                    <HyperlinkButton/>
                </controls:SettingsCard>
            </controls:SettingsExpander.Items>
        </controls:SettingsExpander>
    </StackPanel>
</ScrollView>

实现方法

  • 通过LiteDBindows.Storage.ApplicationData.Current.LocalSettings实现持久化。
  • 通过修改对应页面的ViewModel中的static元素或者直接修改持久化位置的信息完成页面间信息交换。
  • Windows.Globalization.ApplicationLanguages.PrimaryLanguageOverride获取、修改当前的全局语言。

页面展示

  • 可对性能页面显示项目进行自由的修改、包括显示的元素位置、元素种类。

  • 更多设置,包括全球化等更多应用显示设置。

自实现类

Performance工具目录

LHMSupport命名空间

LHMReader工具类

这个类用于操控LibreHardwareMonitor.Hardware,使用类的封装方法,使用前需要对其进行实例化。

  • 重要方法

    • void Update() {}更新对象所维护的设备信息,在使用对象拥有的设备信息时,需要首先调用该方法,等待该方法完成后才可对其属性进行访问。
  • 重要属性

    • List<CpuInformation> CPU 处理器信息
    • List<GpuInformation> GPU 显卡信息,不处理Nvidia显卡
    • NetworkSpeedInformation Network 网络流量信息
    • List<BatteryInformation> Battery 电池信息
    • List<DiskInformation> Disk 硬盘信息
    • List<MemoryInformation> Memory 内存信息
  • 细节

    • 该工具类存在大量“魔法数字”与硬编码,由于LibreHardwareMonitor.Hardware的特性,暂时无法避免,同时各类计算机平台对应的硬编码也不一致,故此处存在不确定性。
    • List<T>提前给定一个较大的值以防不断申请空间,每次执行List.Clear
    • 注意:不要修改重要属性当中的任何值!

NvmlSupport命名空间

NvidiaApi工具类

这个类是根据官方文档的对一些关键接口实现使用C#语言调用,同时将一些用到的数据类型在此命名空间完成转换。

NvidiaSmi工具类

这个类用于操控Nvml Tool,使用单例模式,使用时需要使用GetInstance获取实例,而不是通过实例化获取实例。

  • 重要方法

    • void Update() {}更新对象所维护的设备信息,在使用对象拥有的设备信息时,需要首先调用该方法,等待该方法完成后才可对其属性进行访问。
  • 重要属性

    • List<GpuInformation> GPU Nvidia显卡信息
    • bool NvidiaSmiIsAvailable = false
  • 细节

    • 如果不存在对应的NvidiaApi,本类调用将不会发生任何作用。
    • List<T>提前给定一个较大的值以防不断申请空间,每次执行List.Clear
    • 注意:不要修改重要属性当中的任何值!

HardwareInfoSupport命名空间

HardwareInfoReader工具类

这个类用于操控Hardware.Info,使用类的封装方法,使用前需要对其进行实例化。

  • 重要方法

    • void Update() {}更新对象所维护的设备信息,在使用对象拥有的设备信息时,需要首先调用该方法,等待该方法完成后才可对其属性进行访问。
  • 重要属性

    • List<NetworkInformation> Network 网络设备工作情况
  • 细节

    • 如果IHardwareInfo不可用,本类调用将不会发生任何作用。
    • List<T>提前给定一个较大的值以防不断申请空间,每次执行List.Clear
    • 注意:不要修改重要属性当中的任何值!

Information命名空间

TotalInformation工具类

这个类是用于数据整合,对收集到的信息进行聚合分析,同时添加软件工作情况。该类为静态类,使用方法时请使用其静态方法。

  • 重要方法

    • void Update() {}更新对象所维护的设备信息(Monitor页面使用),在使用对象拥有的设备信息时,需要首先调用该方法,等待该方法完成后才可对其属性进行访问。
    • void UpdateNetwork() {}更新对象所维护的设备信息(Network页面使用),在使用对象拥有的设备信息时,需要首先调用该方法,等待该方法完成后才可对其属性进行访问。
  • 重要属性

    • List<CpuInformation> CPU 处理器信息,实际上来源于LibreReader
    • List<GpuInformation> GPU 所有显卡信息,聚合自OtherGPUNvidiaGPU
    • List<GpuInformation> OtherGPU 显卡信息,实际上来源于LibreReader
    • List<GpuInformation> NvidiaGPU 英伟达显卡信息,实际上来源于NvidiaSmi
    • NetworkSpeedInformation NetworkSpeed 网络流量信息,实际上来源于LibreReader
    • List<NetworkInformation> Network 网络设备信息,实际上来源于HardwareInfoReader
    • List<BatteryInformation> Battery 电池信息,实际上来源于LibreReader
    • List<DiskInformation> Disk 硬盘信息,实际上来源于LibreReader
    • List<MemoryInformation> Memory 内存信息,实际上来源于LibreReader
    • List<KeyValuePair<string, string>> Outline 时间等外围信息
    • List<KeyValuePair<string, string>> RunTimeInfo 程序运行信息
  • 细节

    • List<T>提前给定一个较大的值以防不断申请空间,每次执行List.Clear
    • 注意:不要修改重要属性当中的任何值!

AWCC工作目录

AWCC命名空间

AWCCWMI

这个类是用于管理Dell G15系列的AWCCWmiMethodFunction,基于WMI接口,获取、控制该系列的传感器信息、风扇转速。基于项目tcc-g15wmie2设计得到,再次感谢tcc-g15提供的接口信息。类采用静态类设计,在第一次使用类的时候会自动查找到对应的句柄。

  • 重要方法
    • bool IsAvailable() {} AWCC是否就绪
    • uint GetFanRPM(uint fanId) {} 获取给定的FanId的转速。
    • uint GetFanRPMPercent(uint fanId) {} 获取给定的FanId的转速百分比,此方法无效。
    • uint GetSensorTemperature(uint sensorId) {} 获取给定的sensorId的传感器的值,单位为摄氏度。
    • bool ApplyThermalMode(ThermalMode mode) {} 根据给定的ThermalMode.mode设置工作模式。
    • bool SetAddonSpeedPercent(uint fanId, uint addonPercent) {} 设置给定的FanId的转速百分比addonPercent(0x00-0xff)。
  • 重要属性
    • string ErrorMsg 若发生错误则将错误原因填入,默认值为""
    • uint CpuFanId 处理器风扇Id
    • uint GpuFanId 显卡风扇Id
    • uint CpuSensorId 处理器温度传感器Id
    • uint GpuSensorId 显卡温度传感器Id
    • ThermalMode Mode 目前工作状态
  • 细节
    • 每次启动会将系统强制工作在平衡模式ThermalMode.Balanced,这是因为不存在模式查询的接口。
    • 注意:不要修改重要属性当中的任何值!

Tools工作目录

performance_monitor_winui3.Tools命名空间

StringResource

这个类是用于管理resw文件的,用于取出其种预定义的文本对,其会根据当前的语言动态选择。

  • 重要方法
    • string Get(string key) 返回key对应的文本值。

Utils

这个类用于管理一些本项目中频繁用到的方法,采用静态类封装。

  • 重要方法
    • string ByteFormat(double value, Unit unit) 将给定的数值value按照baseNumber以及当前单位unit转化为可3位显示的最小单位,并附上对应的单位字符。
    • string TimeSpan2String(TimeSpan value)TimeSpan转为时间间隔的字符表示,eg: "2days, 10:00:01"、"1day, 10:00:01"、"10:00:01"。
    • TextBlock AddTitle2Grid(Grid grid, string text, int row, Color fontColor, int fontSize = 16, double height = 1.2) 将一个装有TextBlockGrid放入给定的grid的对应行处,这个函数会自动为grid添加对应的行说明、列说明,并返回TextBlock对象。
    • Tuple<TextBlock, TextBlock> AddPairGrid2Grid(Grid grid, string keyStr, string valueStr, int row, int keySize = 4, int valueSize = 6, int fontSize = 14, double height = 1.2) 将一个装有以TextBlock表示的key/value的键值对的Grid放入给定的grid的对应行处,这个函数会自动为grid添加对应的行说明、列说明,并返回这两个TextBlock对象。
    • Tuple<TextBlock, TextBlock> AddPairWithProgressBarGrid2Grid(Grid grid, string keyStr, int val, int row, string? showValue = null, int keySize = 4, int progressBarSize = 5, int valueSize = 1, int fontSize = 14, double height = 1.2) 将一个装有以TextBlock表示的key/value的键值对的Grid放入给定的grid的对应行处,并带有进度条,这个函数会自动为grid添加对应的行说明、列说明,并返回这两个TextBlock对象。
    • ProgressRing AddLoadingProgressBar2Grid(Grid grid, int row) 将一个加载进度条放在grid的对应行处,并返回该进度条。
    • void SetProgressBar(ProgressBar progressBar, int value) 设置根据value设置progressBar的样式。
    • string GetProgressString(int value) 返回一个字符表示的进度条,eg:"[▉87%]"
    • void SimpleToast(string title, string message) 发起一个只包含标题、消息的Toast
  • 重要属性
    • enum Unit 单位的枚举类型。
    • int baseNumber 单位基数,默认为1024。
    • string[] postfix 单位的表示。
    • char[] ProgressChars 进度条的字符表示。

开发计划

任务 完成情况
硬件工作情况监控 Done
硬件信息收集方式与硬件无关
硬件信息图表展示
网络监控 Done
网络信息收集方式与硬件无关 Done
Dell AWCC 集成 Done
待办列表 Done
待办提醒
快速指令 Done
日程表 Done
日程提醒
网络报文发送器

Q&A

  • 为什么使用Windows SDK 1.5
    • Windows SDK 1.5具有与新一代Windows较为统一的风格
    • 社区较为活跃,但需要注意的一点是Windows SDK 1.5没有对应的设计器、页面预览器。
  • 为什么提出这个项目?
    • 作为本人入门Windows SDK 1.5/Windows编程的一个小项目(所以难免存在不合理的地方,请指正)
    • 作为本人平时需要的工具的集成,加速工作流
  • 为什么我在使用软件监控时硬件信息完全不对?
    • 由于在硬件信息收集的时候存在大量的魔法数字,故难免存在
    • 目前的唯一解决方案是根据实际情况,修改LHMReader工具类,只需要修改其中的DataUpdate就可以解决该问题

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages