WPF Dashboard儀錶盤控制項的實現

来源:http://www.cnblogs.com/zhidanfeng/archive/2017/06/16/7029509.html
-Advertisement-
Play Games

1、確定控制項應該繼承的基類 從錶面上看,目前WPF自帶常用控制項中,沒有一個是接近這個表盤控制項的,但將該控制項拆分就能夠發現,該控制項的每個子部分都是在WPF中存在的,因此我們需要將各個子控制項組合才能形成這個表盤控制項,因此我們直接定義一個Dashboard類,繼承自Control類。 2、設置Dashbo ...


1、確定控制項應該繼承的基類

從錶面上看,目前WPF自帶常用控制項中,沒有一個是接近這個表盤控制項的,但將該控制項拆分就能夠發現,該控制項的每個子部分都是在WPF中存在的,因此我們需要將各個子控制項組合才能形成這個表盤控制項,因此我們直接定義一個Dashboard類,繼承自Control類。

2、設置Dashboard的樣式

<Style TargetType="{x:Type local:Dashboard}">
	<Setter Property="BorderBrush" Value="Black" />
	<Setter Property="BorderThickness" Value="1" />
	<Setter Property="Background" Value="Transparent" />
	<Setter Property="SnapsToDevicePixels" Value="True" />
	<Setter Property="UseLayoutRounding" Value="True" />
	<Setter Property="HorizontalContentAlignment" Value="Left" />
	<Setter Property="VerticalContentAlignment" Value="Center" />
	<Setter Property="Template">
		<Setter.Value>
			<ControlTemplate TargetType="{x:Type local:Dashboard}">
				<Grid>
					
				</Grid>
			</ControlTemplate>
		</Setter.Value>
	</Setter>
</Style>

 主要註意的是,因為我們還不知道Dashboard內部到底有哪些東西,因此這裡先放置了一個Grid,後面所有的代碼將在<Grid></Grid>中編寫

3、確定控制項的內部基本構造

該表盤控制項從錶面上看去,共由三個部分組成

  • 有文字顯示的刻度
  • 有進度展示的圓弧(紅色與灰色部分的圓弧)
  • 中間偏下的內容展示區域
確定內部的基本組成後,就會發現一個問題,WPF中貌似沒有能顯示文字的刻度這樣的一個控制項,也沒有②中描述的這麼一個控制項。很明顯①、②也是由各個子控制項組合而成的。 雖然WPF中沒有①中這樣的控制項,但我們知道有PathListBox與Arc這樣的一個控制項,Arc應該都知道,就是一段圓弧,但是PathListBox可能就有點陌生了,下麵在正式講解Dashboard控制項前,有必要講解一個PathListBox。

3.1、PathListBox

從控制項字面上描述來看Path指的是路徑,ListBox指的是一個列表。那麼PathListBox組合起來就是按照一定的路徑,來顯示列表中的各個Item,下麵使用具體代碼來認識一下這個控制項 ①、命名空間 在WPF預設的System.Windows.Controls下麵是找不到PathListBox的,需引入Microsoft.Expression.Controls.dll,然後在xaml中定義命名空間的別名
xmlns:ec="http://schemas.microsoft.com/expression/2010/controls"

②、具體用法

既然是按照一定路徑排列各個Item,那肯定得先定義一個Path路徑,這裡先定義一個長500的直線Path
<Path x:Name="path" Data="M0,0 500,0" Stroke="Black" StrokeThickness="1" />

然後放置PathListBox,在PathListBox的LayoutPath中去設置PathListBox應該按照哪個路徑去排列,在ItemsTemplate中設置每個Item子項應該呈現成什麼效果,最後在後臺設置PathListBox的ItemsSource,設置PathListBox一共有幾個Item子項。完整代碼如下:

<Grid VerticalAlignment="Center">
	<Path x:Name="path" Data="M0,0 500,0" Stroke="Black" StrokeThickness="1" />
	<ec:PathListBox x:Name="pathListBox">
		<ec:PathListBox.ItemTemplate>
			<DataTemplate>
				<Border Width="3" Height="10" Background="Black" SnapsToDevicePixels="True"
						UseLayoutRounding="True" />
			</DataTemplate>
		</ec:PathListBox.ItemTemplate>
		<ec:PathListBox.LayoutPaths>
			<ec:LayoutPath Distribution="Even" Orientation="OrientToPath"
						   SourceElement="{Binding ElementName=path}" />
		</ec:PathListBox.LayoutPaths>
	</ec:PathListBox>
</Grid>

其中Distributeion與Orientation是關鍵屬性,SourceElement指向的就是PathListBox的排列路徑。最終效果如下圖所示:

3.2、Arc

Arc就是圓弧的意思,這個控制項比較簡單,直接貼出代碼 ①、命名控制項 需引入Microsoft.Expression.Drawing.dll,然後在xaml中定義命名空間的別名
xmlns:ec="http://schemas.microsoft.com/expression/2010/controls"

 ②、具體用法

<ed:Arc x:Name="DoubleCircle" ArcThickness="8" ArcThicknessUnit="Pixel"
		EndAngle="120" StartAngle="-120" 
		Width="200" Height="200" Fill="Red"
		Stretch="None" Stroke="Yellow" StrokeThickness="1" />

其中關鍵屬性描述如下:

學習了下PathListBox與Arc的用法後,下麵正式講解Dashboard是如何創建的。

4、正式構建控制項 

4.1、刻度部分 

Dashboard表盤控制項共有2種刻度,一個是長一點的刻度,一個是短一點的刻度。如果我們只是用一個PathListBox是不能達到這種效果的,因此這裡使用了2個PathListBox,一個PathListBox放置短一點的刻度,一個PathListBox放置長一點的刻度,將他們2個疊加放在一起,就能達到這種效果。
4.1.1、長刻度部分 
這裡定義一個從-120°到120°的一個圓弧與一個PathListBox
<!--  刻度盤完整圓弧  -->
<ed:Arc x:Name="LongTickPath" Margin="0" ArcThickness="0" ArcThicknessUnit="Pixel"
		EndAngle="120" StartAngle="-120" Stretch="None" Stroke="Black"
		StrokeThickness="1" />
<!--  長刻度  -->
<ec:PathListBox x:Name="LongTick" IsHitTestVisible="False">
	<ec:PathListBox.ItemTemplate>
		<DataTemplate>
			<Border Width="1" Height="13"
					Background="Black"
					SnapsToDevicePixels="True" UseLayoutRounding="False" />
		</DataTemplate>
	</ec:PathListBox.ItemTemplate>
	<ec:PathListBox.LayoutPaths>
		<ec:LayoutPath Distribution="Even" Orientation="OrientToPath"
					   SourceElement="{Binding ElementName=LongTickPath}" />
	</ec:PathListBox.LayoutPaths>
</ec:PathListBox>

 但是這樣只能看到圓弧,並沒有看到PathListBox的刻度效果,因為PathListBox沒有設置ItemsSource。而且由於我們是在自定義控制項,因此為了設置PathListBox的ItemsSource的值,我們需要在Dashboard定義一個依賴屬性LongTicksInternal,由於我們並不希望用戶能夠在外面能夠設置LongTicksInternal的值,因此在依賴屬性的set的時候,設置其訪問許可權,設置成private,這樣就只能在樣式裡面訪問該依賴屬性,用戶在外面使用的時候是看不到這個依賴屬性的。

#region LongTicksInternal 長刻度集合
public IList<object> LongTicksInternal
{
	get { return (IList<object>)GetValue(LongTicksInternalProperty); }
	private set { SetValue(LongTicksInternalProperty, value); }
}
public static readonly DependencyProperty LongTicksInternalProperty =
	DependencyProperty.Register("LongTicksInternal", typeof(IList<object>), typeof(Dashboard));
#endregion

 定義了該依賴屬性之後,將該依賴屬性給綁定到PathListBox的ItemsSource上面去

ItemsSource="{TemplateBinding ShortTicks}"

綁定了依賴屬性之後還是不能顯示,因為LongTicksInternal目前是空的一個集合,還需要給LongTicksInternal賦值。

public Dashboard()
{
	this.LongTicksInternal = new List<object>();
	for (int i = 0; i < 10; i++)
	{
		this.LongTicksInternal.Add(i);
	}
}

 效果如下:

#region LongTickCount 長刻度個數
public int LongTickCount
{
	get { return (int)GetValue(LongTickCountProperty); }
	set { SetValue(LongTickCountProperty, value); }
}
public static readonly DependencyProperty LongTickCountProperty =
	DependencyProperty.Register("LongTickCount", typeof(int), typeof(Dashboard), new PropertyMetadata(5));
#endregion

 改動下上面的for迴圈代碼,這樣就可以靈活的設置長刻度的個數了。

for (int i = 0; i < this.LongTickCount; i++)
{
	this.LongTicksInternal.Add(i);
}

 4.1.2、短刻度部分

再次定義一個Path與一個PathListBox,並新增一個依賴屬性,用來設置PathListBox的ItemsSource

 

<!--  刻度盤完整圓弧  -->
<ed:Arc x:Name="ShortTickPath" Margin="0" ArcThickness="0" ArcThicknessUnit="Pixel"
		EndAngle="120" StartAngle="-120" Stretch="None" Stroke="Black"
		StrokeThickness="1" />
<!--  長刻度  -->
<ec:PathListBox x:Name="ShortTick" IsHitTestVisible="False"
				ItemsSource="{TemplateBinding ShortTicksInternal}">
	<ec:PathListBox.ItemTemplate>
		<DataTemplate>
			<Border Width="1" Height="8"
					Background="Black"
					SnapsToDevicePixels="True" UseLayoutRounding="False" />
		</DataTemplate>
	</ec:PathListBox.ItemTemplate>
	<ec:PathListBox.LayoutPaths>
		<ec:LayoutPath Distribution="Even" Orientation="OrientToPath"
					   SourceElement="{Binding ElementName=ShortTickPath}" />
	</ec:PathListBox.LayoutPaths>
</ec:PathListBox>

短刻度個數的依賴屬性

#region ShortTicksInternal 短刻度集合
public IList<object> ShortTicksInternal
{
	get { return (IList<object>)GetValue(ShortTicksInternalProperty); }
	set { SetValue(ShortTicksInternalProperty, value); }
}
public static readonly DependencyProperty ShortTicksInternalProperty =
	DependencyProperty.Register("ShortTicksInternal", typeof(IList<object>), typeof(Dashboard));
#endregion

 但由於短刻度會有很多,不可能去細數表盤一共有多少個短刻度,而且如果手動設置所有的短刻度個數,會有一個問題就是短刻度和長刻度不會重合,導致寬的寬,窄的窄。我們不知道所有的短刻度個數,但是我們可以知道2個長刻度之間有多少個短刻度,因此定義一個ShortTickCount,用來設置2個長刻度間的短刻度的個數

#region ShortTickCount 短刻度個數
public int ShortTickCount
{
	get { return (int)GetValue(ShortTickCountProperty); }
	set { SetValue(ShortTickCountProperty, value); }
}
public static readonly DependencyProperty ShortTickCountProperty =
	DependencyProperty.Register("ShortTickCount", typeof(int), typeof(Dashboard), new PropertyMetadata(5));
#endregion

 根據LongTickCount與ShortTickCount,生成ShortTicksInternal

this.ShortTicksInternal = new List<object>();
for (int i = 0; i < (this.LongTickCount - 1) * (this.ShortTickCount + 1) + 1; i++)
{
	this.ShortTicksInternal.Add(new object());
}

 

這裡簡單介紹一下這個演算法:LongTickCount有9個,ShortTickCount有5個,由圖示可以看出,我們可以將表盤刻度分成8份,每一份由1個長刻度和5個短刻度組成,因此每一份的表達式就是【ShortTickCount + 1】,然後總共分為8份,表達式就成了 (LongTickCount - 1) * (ShortTickCount + 1),最後我們發現第9份只有一個長刻度,這其實也是一個短刻度,那麼最終的表達式就是 (LongTickCount - 1) * (ShortTickCount + 1) + 1

微調下Arc的邊框,將其去掉,然後調整下短刻度的Arc的Margin,將其調整成和長刻度的底部水平
<!--  刻度盤完整圓弧  -->
<ed:Arc x:Name="LongTickPath" Margin="0" ArcThickness="0" ArcThicknessUnit="Pixel"
		EndAngle="120" StartAngle="-120" Stretch="None" Stroke="Black"
		StrokeThickness="0" />
<!--  長刻度  -->
<ec:PathListBox x:Name="LongTick" IsHitTestVisible="False"
				ItemsSource="{TemplateBinding LongTicksInternal}">
	<ec:PathListBox.ItemTemplate>
		<DataTemplate>
			<Border Width="1" Height="13"
					Background="Black" VerticalAlignment="Bottom"
					SnapsToDevicePixels="True" UseLayoutRounding="False" />
		</DataTemplate>
	</ec:PathListBox.ItemTemplate>
	<ec:PathListBox.LayoutPaths>
		<ec:LayoutPath Distribution="Even" Orientation="OrientToPath"
					   SourceElement="{Binding ElementName=LongTickPath}" />
	</ec:PathListBox.LayoutPaths>
</ec:PathListBox>
<!--  刻度盤完整圓弧  -->
<ed:Arc x:Name="ShortTickPath" Margin="5" ArcThickness="0" ArcThicknessUnit="Pixel"
		EndAngle="120" StartAngle="-120" Stretch="None" Stroke="Black"
		StrokeThickness="0" />
<!--  長刻度  -->
<ec:PathListBox x:Name="ShortTick" IsHitTestVisible="False"
				ItemsSource="{TemplateBinding ShortTicksInternal}">
	<ec:PathListBox.ItemTemplate>
		<DataTemplate>
			<Border Width="1" Height="8"
					Background="Black" VerticalAlignment="Bottom"
					SnapsToDevicePixels="True" UseLayoutRounding="False" />
		</DataTemplate>
	</ec:PathListBox.ItemTemplate>
	<ec:PathListBox.LayoutPaths>
		<ec:LayoutPath Distribution="Even" Orientation="OrientToPath"
					   SourceElement="{Binding ElementName=ShortTickPath}" />
	</ec:PathListBox.LayoutPaths>
</ec:PathListBox>

終於,刻度的效果出來了

 4.1.3、文字部分

 上一節已經將刻度做出來了,還差一個文字部分。文字部分與刻度部分同理,只不過不顯示成刻度了,需將每個Item的樣式設置成TextBlock

 

<ed:Arc x:Name="NumberPath" Margin="20" ArcThickness="0" ArcThicknessUnit="Pixel"
		EndAngle="120" StartAngle="-120" Stretch="None" />
<!--  刻度上顯示的數字  -->
<ec:PathListBox x:Name="Number" IsHitTestVisible="False"
				ItemsSource="{TemplateBinding NumberListInternal}">
	<ec:PathListBox.ItemTemplate>
		<DataTemplate>
			<TextBlock Text="{Binding}" />
		</DataTemplate>
	</ec:PathListBox.ItemTemplate>
	<ec:PathListBox.LayoutPaths>
		<ec:LayoutPath Distribution="Even" Orientation="OrientToPath"
					   SourceElement="{Binding ElementName=NumberPath}" />
	</ec:PathListBox.LayoutPaths>
</ec:PathListBox>

 

#region NumberListInternal 數字集合
public IList<object> NumberListInternal
{
	get { return (IList<object>)GetValue(NumberListInternalProperty); }
	set { SetValue(NumberListInternalProperty, value); }
}
public static readonly DependencyProperty NumberListInternalProperty =
	DependencyProperty.Register("NumberListInternal", typeof(IList<object>), typeof(Dashboard));
#endregion

由於表盤上面顯示的數字會有不同,因此應該讓其可以設置,因此定義一個最大值與最小值的依賴屬性,表盤上面的文字應該根據這兩個屬性來自動生成

#region Minimum 最小值
/// <summary>
/// 最小值依賴屬性,用於Binding
/// </summary>
public static readonly DependencyProperty MinimumProperty =
	DependencyProperty.Register(
		"Minimum",
		typeof(double),
		typeof(Dashboard),
		new PropertyMetadata(0.0));
/// <summary>
/// 獲取或設置最小值.
/// </summary>
/// <value>最小值.</value>
public double Minimum
{
	get { return (double)GetValue(MinimumProperty); }
	set { SetValue(MinimumProperty, value); }
}
#endregion
#region Maximum 最大值
/// <summary>
/// 最大值依賴屬性,用於Binding
/// </summary>
public static readonly DependencyProperty MaximumProperty =
	DependencyProperty.Register(
		"Maximum",
		typeof(double),
		typeof(Dashboard),
		new PropertyMetadata(100.0));
/// <summary>
/// 獲取或設置最大值.
/// </summary>
/// <value>最大值.</value>
public double Maximum
{
	get { return (double)GetValue(MaximumProperty); }
	set { SetValue(MaximumProperty, value); }
}
#endregion

 由於文字只在長刻度下麵顯示,因此在設置Long的for迴圈中設置的值

this.NumberListInternal = new List<object>();
for (int i = 0; i < this.LongTickCount; i++)
{
	this.NumberListInternal.Add(Math.Round(this.Minimum + (this.Maximum - this.Minimum) / (this.LongTickCount - 1) * i));
	this.LongTicksInternal.Add(i);
}

演算法解析:上面已經說到,我們將表盤刻度分成了8份,那麼 (this.Maximum - this.Minimum) / (this.LongTickCount - 1) 可以得到每一份所代表的值,每一份乘以i,就表示接下來的每份的值,但是表盤不可能永遠都是從0開始的,我們會給它設置最小值,因此得加上Minimum,最後得出來的結果有可能會有小數點,為了省去這個小數點,使用了Math.Round()函數來取整。至此,刻度與數字部分完成了。

 

4.2、進度(當前值)部分

這段圓弧一共由兩個圓弧組成,紅色表示當前值,灰色只是作為底色展示用的,並無太大作用

<!--  刻度盤完整圓弧  -->
<ed:Arc x:Name="DoubleCircle" Margin="50" ArcThickness="1" ArcThicknessUnit="Pixel"
		EndAngle="120"
		SnapsToDevicePixels="True"
		StartAngle="-120"
		Stretch="None" Stroke="#746E7A" StrokeThickness="1" UseLayoutRounding="True" />
<!--  刻度盤當前值對應的圓弧  -->
<ed:Arc x:Name="PART_IncreaseCircle" Margin="50" ArcThickness="1" ArcThicknessUnit="Pixel"
		RenderTransformOrigin="0.5,0.5"
		StartAngle="-120" EndAngle="10"
		Stretch="None" Stroke="Yellow" StrokeThickness="1" />

 效果如下:

至此,控制項的內部構造基本完成,接下來完成最後一部分,就是根據表盤當前值來設置黃色部分的角度,從而實現儀錶盤的效果。 上面我們已經定義了最大值與最小值,還差一個當前值Value,因此定義一個Value的依賴屬性
#region Value 當前值
/// <summary>
/// 最大值依賴屬性,用於Binding
/// </summary>
public static readonly DependencyProperty ValueProperty =
	DependencyProperty.Register(
		"Value",
		typeof(double),
		typeof(Dashboard),
		new PropertyMetadata(0.0, new PropertyChangedCallback(OnValuePropertyChanged)));
/// <summary>
/// 獲取或設置當前值
/// </summary>
public double Value
{
	get { return (double)GetValue(ValueProperty); }
	set { SetValue(ValueProperty, value); }
}
private static void OnValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
	//Dashboard dashboard = d as Dashboard;
	//dashboard.OldAngle = dashboard.Angle;
	//dashboard.SetAngle();
	//dashboard.TransformAngle();
}
#endregion

之外為了設置圓弧的角度,還需要新增一個Angle依賴屬性

#region Angle
public double Angle
{
	get { return (double)GetValue(AngleProperty); }
	set { SetValue(AngleProperty, value); }
}
public static readonly DependencyProperty AngleProperty =
	DependencyProperty.Register("Angle", typeof(double), typeof(Dashboard), new PropertyMetadata(0d));
#endregion

在代碼中,根據Value的值,自動設置Angle

private void SetAngle()
{
	var diff = this.Maximum - this.Minimum;
	var valueDiff = this.Value - this.Minimum;
	this.Angle = -120 + (120 - (-120)) / diff * valueDiff;
}

演算法解析:結束角度-起始角度可以得出圓弧總共經過的角度值,除以最大值與最小值的差值,得到1°對應的數值,乘以當前值與最小值的差值就可以得到差值所對應的角度總和了。由於起始角度不固定,因此最終的角度值應該是:起始角度+差值角度和

最終,我們的效果實現了:

這裡面有一個不足的地方就是起始角度和結束角度硬編碼成-120和120了,為了靈活性,可以將其設置為2個依賴屬性,這個就自己去弄吧,這裡就不貼出代碼了。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 文件描述符(重點) 在Linux系統中一切皆可以看成是文件,文件又可分為:普通文件、目錄文件、鏈接文件和設備文件。文件描述符(file descriptor)是內核為了高效管理已被打開的文件所創建的索引,其是一個非負整數(通常是小整數),用於指代被打開的文件,所有執行I/O操作的系統調用都通過 ...
  • 最近在將項目從.net 遷移到.net core環境中,遷移完成後,發佈於Windows平臺上進行測試,所有功能均能正常運行。 為了項目能夠在正式環境也能正常運行,提前進行Linux環境部署(Centos7)預發佈,就在預發佈後進行代碼的基本測試後, 發現日誌中出現了string轉datetime錯 ...
  • await 關鍵字不會創建新的線程,而是由Task任務或是FCL中的xxxAsync等方法創建的線程,而且這裡創建的線程都是基於線程池創建的工作線程,屬於後臺線程。 await關鍵字會阻塞/暫停調用它的方法,也即下麵的 Phycology 方法.當阻塞其調用方法的時候,程式會回到UI線程中去執行,也 ...
  • 才疏學淺,勤奮一點。——無感 關於Socket技術的細緻講解,博客園中已經有不少文章可以學習。我這主要是就自己在開發過程中做的一個數據對接程式設計的總結。 首先,定義介面。 1:IStructData 數據結構介面 包含兩個方法,一個是設置校驗位元組,一個是校驗方法。 1 interface IStr ...
  • supervisor 介紹: 這是一款用python編寫的進程管理工具,可以守護他管理的所有進程,防止異常退出,以及提供一個可視化的web界面來手動管理,打開關閉重啟各種應用,界面如下: 關於在centos上安裝supervisor: 1、通過yum安裝: 2、配置supervisor: 我們去用v ...
  • Asp.net core 以及MVC4.6中如何全局對用戶輸入做Trim空白處理?本文實例分享 ...
  • 最近項目需要做一個客戶查詢狀態系統,當前上位機缺少服務功能,於是找到了networkcomms 開源框架,作為項目使用. 最新版networkcomms 下載地址:https://github.com/MarcFletcher/NetworkComms.Net 下載直接vs打開 新建伺服器端 在別的 ...
  • 人總是很忙的,但是一個人就是一個人,不存在分身術。 假設有個人王大柱,他是光明中學的校長,還是光明村的村委會成員,同時還是他兒子的父親。 那麼我們可以這麼想:王大柱是一個類的具體的實現對象,這類名叫“王大柱類”,而王大柱類實現了三個介面:“I光明中學校長”、“I光明村村委會成員”、“I父親”。 畫圖 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...