WPF 上位機開發模板

WPF 上位機開發模板

WPF上位機開發模板,集成了基礎操作菜單、海康視覺實時圖像界面、串口通訊、網口通訊、主流PLC通訊、數據存儲、圖片存儲、參數配置、權限管理、第三方webapi接口接入、數據追溯與查詢等功能。

一、項目結構

WpfSupervisor/
├── Models/                  # 數據模型
│   ├── DeviceModels.cs
│   ├── ImageModel.cs
│   ├── LogModel.cs
│   ├── ParameterModel.cs
│   └── UserModel.cs
├── Services/                # 服務層
│   ├── Communication/
│   │   ├── ComService.cs
│   │   ├── EthernetService.cs
│   │   ├── PlcService.cs
│   │   └── WebApiService.cs
│   ├── Database/
│   │   ├── DatabaseService.cs
│   │   └── ImageStorage.cs
│   ├── HikVision/
│   │   └── HikVisionService.cs
│   ├── Security/
│   │   ├── AuthService.cs
│   │   └── PermissionService.cs
│   └── Utility/
│       ├── ConfigManager.cs
│       └── Logger.cs
├── ViewModels/              # 視圖模型
│   ├── MainViewModel.cs
│   ├── CommunicationViewModel.cs
│   ├── ImageViewModel.cs
│   ├── ParameterViewModel.cs
│   └── UserViewModel.cs
├── Views/                   # 視圖
│   ├── MainWindow.xaml
│   ├── CommunicationView.xaml
│   ├── ImageView.xaml
│   ├── ParameterView.xaml
│   └── LoginView.xaml
├── Helpers/                 # 輔助類
│   ├── RelayCommand.cs
│   └── EnumExtensions.cs
└── App.xaml.cs              # 應用程序入口

二、核心代碼實現

1. 數據模型 (Models/)

// DeviceModels.cs
public class PlcDevice
{public string Id { get; set; }public string Name { get; set; }public string IpAddress { get; set; }public int Port { get; set; }public string Protocol { get; set; } // Modbus, S7, etc.
}public class SerialDevice
{public string Id { get; set; }public string Name { get; set; }public string PortName { get; set; }public int BaudRate { get; set; }public Parity Parity { get; set; }public int DataBits { get; set; }public StopBits StopBits { get; set; }
}// ImageModel.cs
public class CapturedImage
{public string Id { get; set; }public byte[] ImageData { get; set; }public DateTime CaptureTime { get; set; }public string DeviceId { get; set; }public string FilePath { get; set; }
}// LogModel.cs
public class SystemLog
{public string Id { get; set; }public DateTime Timestamp { get; set; }public string Level { get; set; } // Info, Warning, Errorpublic string Message { get; set; }public string UserId { get; set; }
}// ParameterModel.cs
public class SystemParameter
{public string Id { get; set; }public string Key { get; set; }public string Value { get; set; }public string Description { get; set; }public string Category { get; set; }
}// UserModel.cs
public class User
{public string Id { get; set; }public string Username { get; set; }public string PasswordHash { get; set; }public string FullName { get; set; }public string Role { get; set; } // Admin, Operator, etc.public DateTime LastLogin { get; set; }
}

2. 服務層 (Services/)

2.1 通信服務
// ComService.cs
public class ComService : IDisposable
{private SerialPort _serialPort;public event Action<string> DataReceived;public bool IsOpen => _serialPort?.IsOpen ?? false;public void Open(SerialDevice device){_serialPort = new SerialPort(device.PortName, device.BaudRate, device.Parity, device.DataBits, device.StopBits);_serialPort.DataReceived += (s, e) => {try{var data = _serialPort.ReadExisting();DataReceived?.Invoke(data);}catch (Exception ex){Logger.LogError($"串口數據接收錯誤: {ex.Message}");}};_serialPort.Open();}public void Close() => _serialPort?.Close();public void Send(string data) => _serialPort?.Write(data);public void Dispose() => Close();
}// EthernetService.cs
public class EthernetService : IDisposable
{private TcpClient _tcpClient;private NetworkStream _stream;public event Action<string> DataReceived;public bool IsConnected => _tcpClient?.Connected ?? false;public async Task ConnectAsync(string ipAddress, int port){_tcpClient = new TcpClient();await _tcpClient.ConnectAsync(ipAddress, port);_stream = _tcpClient.GetStream();_ = ReceiveDataAsync();}private async Task ReceiveDataAsync(){try{var buffer = new byte[1024];while (_stream != null && _stream.CanRead){int bytesRead = await _stream.ReadAsync(buffer, 0, buffer.Length);var data = Encoding.ASCII.GetString(buffer, 0, bytesRead);DataReceived?.Invoke(data);}}catch (Exception ex){Logger.LogError($"以太網數據接收錯誤: {ex.Message}");}}public void Send(string data){if (_stream == null || !_stream.CanWrite) return;var bytes = Encoding.ASCII.GetBytes(data);_stream.Write(bytes, 0, bytes.Length);}public void Disconnect() => _tcpClient?.Close();public void Dispose(){Disconnect();_stream?.Close();}
}// PlcService.cs (使用S7.Net庫示例)
public class PlcService : IDisposable
{private S7.Net.PLC _plc;public event Action<string> DataReceived;public bool IsConnected => _plc?.IsConnected ?? false;public async Task ConnectAsync(PlcDevice device){_plc = new S7.Net.PLC(device.Protocol == "S7" ? S7.Net.CpuType.S71200 : S7.Net.CpuType.S7300, device.IpAddress, device.Port);await Task.Run(() => _plc.Open());}public async Task<T> ReadAsync<T>(string address){if (!IsConnected) throw new InvalidOperationException("PLC未連接");return await Task.Run(() => (T)_plc.Read(address));}public async Task WriteAsync<T>(string address, T value){if (!IsConnected) throw new InvalidOperationException("PLC未連接");await Task.Run(() => _plc.Write(address, value));}public void Dispose() => _plc?.Close();
}// WebApiService.cs
public class WebApiService
{private readonly HttpClient _httpClient;private readonly string _baseUrl;public WebApiService(string baseUrl){_baseUrl = baseUrl.EndsWith("/") ? baseUrl : baseUrl + "/";_httpClient = new HttpClient();}public async Task<T> GetAsync<T>(string endpoint){var response = await _httpClient.GetAsync(_baseUrl + endpoint);response.EnsureSuccessStatusCode();return await response.Content.ReadAsAsync<T>();}public async Task PostAsync<T>(string endpoint, object data){var content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");var response = await _httpClient.PostAsync(_baseUrl + endpoint, content);response.EnsureSuccessStatusCode();}
}
2.2 數據庫服務
 
// DatabaseService.cs
public class DatabaseService
{private readonly string _connectionString;private SQLiteConnection _connection;public DatabaseService(string dbPath){_connectionString = $"Data Source={dbPath};Version=3;";InitializeDatabase();}private void InitializeDatabase(){_connection = new SQLiteConnection(_connectionString);_connection.Open();// 創建表ExecuteNonQuery(@"CREATE TABLE IF NOT EXISTS SystemLogs (Id TEXT PRIMARY KEY,Timestamp TEXT,Level TEXT,Message TEXT,UserId TEXT);CREATE TABLE IF NOT EXISTS SystemParameters (Id TEXT PRIMARY KEY,Key TEXT,Value TEXT,Description TEXT,Category TEXT);CREATE TABLE IF NOT EXISTS Users (Id TEXT PRIMARY KEY,Username TEXT,PasswordHash TEXT,FullName TEXT,Role TEXT,LastLogin TEXT);");}public void ExecuteNonQuery(string sql, params object[] parameters){using (var cmd = new SQLiteCommand(sql, _connection)){for (int i = 0; i < parameters.Length; i++){cmd.Parameters.AddWithValue($"@p{i}", parameters[i]);}cmd.ExecuteNonQuery();}}public T ExecuteScalar<T>(string sql, params object[] parameters){using (var cmd = new SQLiteCommand(sql, _connection)){for (int i = 0; i < parameters.Length; i++){cmd.Parameters.AddWithValue($"@p{i}", parameters[i]);}return (T)cmd.ExecuteScalar();}}public DataTable ExecuteQuery(string sql, params object[] parameters){using (var cmd = new SQLiteCommand(sql, _connection)){for (int i = 0; i < parameters.Length; i++){cmd.Parameters.AddWithValue($"@p{i}", parameters[i]);}var adapter = new SQLiteDataAdapter(cmd);var table = new DataTable();adapter.Fill(table);return table;}}public void Dispose(){_connection?.Close();}
}// ImageStorage.cs
public class ImageStorage
{private readonly string _imageFolderPath;private readonly DatabaseService _dbService;public ImageStorage(string folderPath, DatabaseService dbService){_imageFolderPath = folderPath;Directory.CreateDirectory(_imageFolderPath);_dbService = dbService;}public async Task SaveImageAsync(CapturedImage image){// 保存到數據庫var imageId = Guid.NewGuid().ToString();var parameters = new object[]{imageId,image.ImageData != null ? Convert.ToBase64String(image.ImageData) : null,image.CaptureTime.ToString("o"),image.DeviceId,image.FilePath};_dbService.ExecuteNonQuery(@"INSERT INTO Images (Id, Data, CaptureTime, DeviceId, FilePath)VALUES (@p0, @p1, @p2, @p3, @p4);", parameters);// 保存文件if (image.ImageData != null){var filePath = Path.Combine(_imageFolderPath, $"{imageId}.jpg");await File.WriteAllBytesAsync(filePath, image.ImageData);// 更新數據庫中的文件路徑_dbService.ExecuteNonQuery(@"UPDATE Images SET FilePath = @p0 WHERE Id = @p1;", filePath, imageId);}}public async Task<CapturedImage> GetImageAsync(string id){var row = _dbService.ExecuteQuery("SELECT * FROM Images WHERE Id = @p0;", id).Rows[0];return new CapturedImage{Id = row["Id"].ToString(),ImageData = row["Data"] != DBNull.Value ? Convert.FromBase64String(row["Data"].ToString()) : null,CaptureTime = DateTime.Parse(row["CaptureTime"].ToString()),DeviceId = row["DeviceId"].ToString(),FilePath = row["FilePath"]?.ToString()};}
}
2.3 海康視覺服務
// HikVisionService.cs
public class HikVisionService
{private readonly HttpClient _httpClient;private readonly string _baseUrl;private readonly string _username;private readonly string _password;public event Action<byte[]> ImageReceived;public HikVisionService(string baseUrl, string username, string password){_baseUrl = baseUrl.EndsWith("/") ? baseUrl : baseUrl + "/";_username = username;_password = password;_httpClient = new HttpClient();// 登錄Login();}private void Login(){var loginData = new Dictionary<string, string>{{"action", "login"},{"user", _username},{"password", _password}};var content = new FormUrlEncodedContent(loginData);var response = _httpClient.PostAsync(_baseUrl + "login", content).Result;response.EnsureSuccessStatusCode();}public async Task StartRealTimeImage(){// 啟動實時圖像流var streamResponse = await _httpClient.GetAsync($"{_baseUrl}stream");streamResponse.EnsureSuccessStatusCode();var stream = await streamResponse.Content.ReadAsStreamAsync();// 處理圖像流數據using (var reader = new BinaryReader(stream)){while (true){// 實際實現需要解析海康威視的流協議// 這里簡化處理var buffer = reader.ReadBytes(1024);if (buffer.Length > 0){// 解碼圖像數據var imageData = DecodeHikVisionImage(buffer);ImageReceived?.Invoke(imageData);}}}}private byte[] DecodeHikVisionImage(byte[] buffer){// 實際實現需要根據海康威視的圖像編碼格式解碼// 這里簡化處理,直接返回原始數據return buffer;}
}
2.4 安全服務
 
// AuthService.cs
public class AuthService
{private readonly DatabaseService _dbService;public AuthService(DatabaseService dbService){_dbService = dbService;}public async Task<User> LoginAsync(string username, string password){var userRow = _dbService.ExecuteQuery("SELECT * FROM Users WHERE Username = @p0;", username).Rows[0];var user = MapUserFromRow(userRow);// 驗證密碼if (VerifyPassword(password, user.PasswordHash)){user.LastLogin = DateTime.UtcNow.ToString("o");await UpdateUserAsync(user);return user;}return null;}private bool VerifyPassword(string inputPassword, string storedHash){// 實際實現應使用安全的密碼哈希驗證// 這里簡化處理return inputPassword == storedHash; }public async Task<User> GetUserAsync(string userId){var row = _dbService.ExecuteQuery("SELECT * FROM Users WHERE Id = @p0;", userId).Rows[0];return MapUserFromRow(row);}private User MapUserFromRow(DataRow row){return new User{Id = row["Id"].ToString(),Username = row["Username"].ToString(),PasswordHash = row["PasswordHash"].ToString(),FullName = row["FullName"].ToString(),Role = row["Role"].ToString(),LastLogin = row["LastLogin"]?.ToString()};}private async Task UpdateUserAsync(User user){_dbService.ExecuteNonQuery(@"UPDATE Users SET LastLogin = @p0 WHERE Id = @p1;",user.LastLogin, user.Id);}
}// PermissionService.cs
public class PermissionService
{private readonly DatabaseService _dbService;public PermissionService(DatabaseService dbService){_dbService = dbService;}public async Task<bool> HasPermissionAsync(string userId, string permission){// 從數據庫查詢用戶權限var hasPermission = await _dbService.ExecuteScalarAsync<bool>("SELECT COUNT(*) > 0 FROM UserPermissions WHERE UserId = @p0 AND Permission = @p1;",userId, permission);return hasPermission;}public async Task<IEnumerable<string>> GetUserPermissionsAsync(string userId){var permissions = await _dbService.ExecuteQueryAsync("SELECT Permission FROM UserPermissions WHERE UserId = @p0;", userId);return permissions.Select(r => r["Permission"].ToString());}
}

3. 視圖模型 (ViewModels/)

// MainViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{private readonly IEventAggregator _eventAggregator;private readonly AuthService _authService;private readonly PermissionService _permissionService;private object _currentView;private User _currentUser;public object CurrentView{get => _currentView;set { _currentView = value; OnPropertyChanged(); }}public User CurrentUser{get => _currentUser;private set { _currentUser = value; OnPropertyChanged(); }}public ICommand LoginCommand { get; }public ICommand LogoutCommand { get; }public MainViewModel(IEventAggregator eventAggregator,AuthService authService,PermissionService permissionService){_eventAggregator = eventAggregator;_authService = authService;_permissionService = permissionService;LoginCommand = new RelayCommand(Login);LogoutCommand = new RelayCommand(Logout, CanLogout);}private async void Login(){// 實際實現應顯示登錄對話框var loginView = new LoginView();if (loginView.ShowDialog() == true){var user = await _authService.LoginAsync(loginView.Username, loginView.Password);if (user != null){CurrentUser = user;CurrentView = new ShellViewModel(_eventAggregator, user).View;_eventAggregator.Publish(new UserLoggedInEvent(user));}}}private void Logout(){CurrentUser = null;CurrentView = new LoginView();_eventAggregator.Publish(new UserLoggedOutEvent());}private bool CanLogout() => CurrentUser != null;public event PropertyChangedEventHandler PropertyChanged;protected void OnPropertyChanged([CallerMemberName] string propertyName = null){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}
}// CommunicationViewModel.cs
public class CommunicationViewModel : INotifyPropertyChanged
{private readonly ComService _comService;private readonly EthernetService _ethernetService;private readonly PlcService _plcService;private readonly WebApiService _webApiService;private SerialDevice _selectedSerialDevice;private PlcDevice _selectedPlcDevice;public ObservableCollection<SerialDevice> SerialDevices { get; } = new();public ObservableCollection<PlcDevice> PlcDevices { get; } = new();public SerialDevice SelectedSerialDevice{get => _selectedSerialDevice;set { _selectedSerialDevice = value; OnPropertyChanged();OpenSerialPort();}}public PlcDevice SelectedPlcDevice{get => _selectedPlcDevice;set { _selectedPlcDevice = value; OnPropertyChanged();ConnectPlc();}}public ICommand RefreshDevicesCommand { get; }public ICommand SendSerialCommand { get; }public ICommand ReadPlcCommand { get; }public ICommand WritePlcCommand { get; }public CommunicationViewModel(ComService comService,EthernetService ethernetService,PlcService plcService,WebApiService webApiService){_comService = comService;_ethernetService = ethernetService;_plcService = plcService;_webApiService = webApiService;RefreshDevicesCommand = new RelayCommand(RefreshDevices);SendSerialCommand = new RelayCommand(SendSerialData, CanSendSerial);ReadPlcCommand = new RelayCommand(ReadPlcData, CanReadPlc);WritePlcCommand = new RelayCommand(WritePlcData, CanWritePlc);LoadDevices();}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/79036.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/79036.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/79036.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

瀏覽器插件,提示:此擴展程序未遵循 Chrome 擴展程序的最佳實踐,因此已無法再使用

1、發現的問題如下&#xff1a; 如果你是比較新的 Chrome 135.0.7049.42&#xff08;含&#xff09;以上版本的話&#xff0c;可以通過修改 chorme://flags 來徹底解決。 2、在瀏覽器分別輸入兩個地址&#xff1a; chrome://flags/#extension-manifest-v2-deprecation-disable…

【原創】從s3桶將對象導入ES建立索引,以便快速查找文件

總體功能&#xff1a; 這段程序的作用是&#xff1a; 從指定的S3桶中讀取所有對象的元數據&#xff08;文件名、大小、最后修改時間、存儲類型、ETag等&#xff09;&#xff0c;并把這些信息寫入到Elasticsearch&#xff08;ES&#xff09;中&#xff0c;建立索引&#xff0c…

git 查看用戶信息

在 Git 中查看用戶信息是一項常見的任務&#xff0c;可以幫助你確認當前倉庫的配置或全局的 Git 配置是否正確設置。你可以通過多種方式來查看這些信息。 查看全局用戶信息 全局用戶信息是應用于所有 Git 倉庫的默認設置。要查看全局用戶信息&#xff0c;可以使用以下命令&am…

制作JDK17 arm64基礎鏡像,解決字體安裝問題

1、下載jdk17 arm64的安裝包 官網下載地址 2、編寫Dockerfile 圖形驗證碼生成需要使用到相關字體&#xff0c;所以基礎鏡像把字體相關也安裝上。 # 基礎鏡像 FROM arm64v8/centos:8.4.2105MAINTAINER hqh# 換源 RUN sed -i s|^mirrorlist|#mirrorlist|g /etc/yum.repos.d/…

人工智能數學基礎(三):微積分初步

微積分作為數學的重要分支&#xff0c;為人工智能的發展提供了堅實的理論基礎。從理解數據的變化趨勢到優化模型參數&#xff0c;微積分的應用貫穿其中。本文將深入探討微積分的核心概念&#xff0c;并結合 Python 編程實例&#xff0c;助力大家輕松掌握這些關鍵知識點。資源綁…

區塊鏈密碼學核心

文章目錄 概要1. 基礎密碼學哈希函數&#xff08;Hash Function&#xff09;對稱加密與非對稱加密數字簽名&#xff08;Digital Signature&#xff09;密鑰管理 2. 區塊鏈專用密碼學技術零知識證明&#xff08;Zero-Knowledge Proof, ZKP&#xff09;同態加密&#xff08;Homom…

Java后端開發day39--方法引用

&#xff08;以下內容全部來自上述課程&#xff09; 1.1 含義 把已經有的方法拿過來用&#xff0c;當作函數式接口中抽象方法的方法體。 已經有的方法&#xff1a;可以是Java自己寫的&#xff0c;也可以是第三方的。 示例語句&#xff1a; &#xff1a;&#xff1a;是方法引…

目前市面上知名的數據采集器

程序員愛自己動手打造一切&#xff0c;但這樣離錢就會比較遠。 市面上知名的數據采集工具 數據采集工具&#xff08;也稱為網絡爬蟲或數據抓取工具&#xff09;在市場上有很多選擇&#xff0c;以下是目前比較知名和廣泛使用的工具分類介紹&#xff1a; 一、開源免費工具 Scra…

TP5兼容達夢國產數據庫

1.首先數據庫安裝&#xff0c;部署時需配置大小寫不敏感 2.安裝PHP達夢擴展&#xff0c;一定要是對應版本&#xff08;兼容操作系統&#xff09;的擴展&#xff0c;否則會出現各種報錯。參考官方文檔&#xff1a;https://eco.dameng.com/document/dm/zh-cn/app-dev/php_php_new…

《解鎖圖像“高清密碼”:超分辨率重建之路》

在圖像的世界里&#xff0c;高分辨率意味著更多細節、更清晰的畫面&#xff0c;就像用高清望遠鏡眺望遠方&#xff0c;一切都纖毫畢現。可現實中&#xff0c;我們常被低分辨率圖像困擾&#xff0c;模糊的監控畫面、老舊照片里難以辨認的面容……不過別擔心&#xff0c;圖像超分…

整合 CountVectorizer 和 TfidfVectorizer 繪制詞云圖

本文分別整合 CountVectorizer 和 TfidfVectorizer 繪制詞云圖 ? CountVectorizer CountVectorizer 是 scikit-learn 中用于 文本特征提取 的一個工具&#xff0c;它的主要作用是將一組文本&#xff08;文本集合&#xff09;轉換為詞頻向量&#xff08;Bag-of-Words&#xf…

Linux 用戶管理

用戶管理是 Linux 系統管理中的重要組成部分&#xff0c;它涉及到用戶和用戶組的創建、刪除、修改以及權限分配等操作。以下是關于用戶和用戶組管理的詳細說明&#xff1a; 一、用戶和用戶組的概念 &#xff08;一&#xff09;用戶&#xff08;User&#xff09; 用戶是系統中…

【HTTP/2和HTTP/3的應用現狀:看不見的革命】

HTTP/2和HTTP/3的應用現狀&#xff1a;看不見的革命 實際上&#xff0c;HTTP/2和HTTP/3已經被眾多著名網站廣泛采用&#xff0c;只是這場革命對普通用戶來說是"無形"的。讓我們揭開這個技術變革的真相。 著名網站的HTTP/2和HTTP/3采用情況 #mermaid-svg-MtfrNDo5DG…

青少年編程與數學 02-018 C++數據結構與算法 16課題、貪心算法

青少年編程與數學 02-018 C數據結構與算法 16課題、貪心算法 一、貪心算法的基本概念定義組成部分 二、貪心算法的工作原理三、貪心算法的優點四、貪心算法的缺點五、貪心算法的應用實例&#xff08;一&#xff09;找零問題問題描述&#xff1a;貪心策略&#xff1a;示例代碼&a…

UE5 Set actor Location和 Set World Location 和 Set Relative Location 的區別

在 Unreal Engine 的藍圖里&#xff0c;SetRelativeLocation、SetWorldLocation 和 SetActorLocation 三個節點雖然都能改變物體位置&#xff0c;但作用對象和坐標空間&#xff08;Coordinate Space&#xff09;不同&#xff1a; 1. SetActorLocation 作用對象&#xff1a;整個…

VINS-FUSION:跑通手機錄制數據

文章目錄 &#x1f4da;簡介&#x1f680;手機錄制數據&#x1f680;跑通數據&#x1f527;啟動rviz&#x1f527;啟動配置&#x1f527;播放rosbag&#x1f3af;跑通結果 &#x1f4da;簡介 利用智能手機的 攝像頭IMU 采集數據&#xff0c;并在 VINS-Fusion&#xff08;視覺慣…

Spring AI在大模型領域的趨勢場景題深度解析

Spring AI在大模型領域的趨勢場景題深度解析 在互聯網大廠Java求職者的面試中&#xff0c;經常會被問到關于Spring AI在大模型領域的趨勢場景的相關問題。本文通過一個故事場景來展示這些問題的實際解決方案。 第一輪提問 面試官&#xff1a;馬架構&#xff0c;歡迎來到我們…

MySQL數據庫全面詳解:從基礎到高級應用

一、數據存儲概述 在計算機系統中&#xff0c;數據可以存儲在多種形式中&#xff1a; 變量&#xff1a;程序中最基本的數據存儲單元 元組&#xff1a;不可變的序列類型&#xff0c;常用于函數返回多個值 列表&#xff1a;有序可變集合&#xff0c;可存儲不同類型元素 字典&…

Redux和MobX有什么區別

Redux 和 MobX 都是用于 React 應用的全局狀態管理庫&#xff0c;但它們在設計理念、使用方式和適用場景等方面存在明顯的區別&#xff0c;下面為你詳細分析&#xff1a; 1. 設計理念 Redux&#xff1a;基于 Flux 架構&#xff0c;遵循單向數據流和純函數式編程的理念。狀態是…

WPF實現類似Microsoft Visual Studio2022界面效果及動態生成界面技術

WPF實現類似VS2022界面效果及動態生成界面技術 一、實現類似VS2022界面效果 1. 主窗口布局與主題 <!-- MainWindow.xaml --> <Window x:Class"VsStyleApp.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x…