C#簡(jiǎn)單配置類(lèi)及數(shù)據(jù)綁定
1、簡(jiǎn)介
本文實(shí)現(xiàn)一個(gè)簡(jiǎn)單的配置類(lèi),原理比較簡(jiǎn)單,適用于一些小型項(xiàng)目。主要實(shí)現(xiàn)以下功能:
- 保存配置到
json
文件 - 從文件或?qū)嵗虞d配置類(lèi)的屬性值
- 數(shù)據(jù)綁定到界面控件
一般情況下,項(xiàng)目都會(huì)提供配置的設(shè)置界面,很少手動(dòng)更改配置文件,所以選擇以json
文件保存配置數(shù)據(jù)。
2、配置基類(lèi)
為了方便管理,項(xiàng)目中的配置一般是按用途劃分到不同的配置類(lèi)中,保存時(shí)也是保存到多個(gè)配置文件。所以,我們需要實(shí)現(xiàn)一個(gè)配置基類(lèi),然后再派生出不同用途的配置類(lèi)。
配置基類(lèi)需要引用 Json.NET
,繼承數(shù)據(jù)綁定基類(lèi) BindableBase
,實(shí)現(xiàn)從其它實(shí)例加載數(shù)據(jù)的功能
基類(lèi)代碼如下:
using Newtonsoft.Json; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; namespace TestConfigDll { /// <summary> /// 配置基類(lèi),實(shí)現(xiàn)配置類(lèi)的加載、保存功能 /// </summary> /// <typeparam name="T"></typeparam> public class ConfigBase<T> : BindableBase where T : class { /// <summary> /// 文件保存路徑 /// </summary> private string filePath = ""; /// <summary> /// 設(shè)置文件保存路徑 /// </summary> /// <param name="filePath"></param> public virtual void SetPath(string filePath) { this.filePath = filePath; } /// <summary> /// 保存到本地文件 /// </summary> public virtual void Save() { string dirStr = Path.GetDirectoryName(filePath); if (!Directory.Exists(dirStr)) { Directory.CreateDirectory(dirStr); } string jsonStr = JsonConvert.SerializeObject(this); File.WriteAllText(filePath, jsonStr); } /// <summary> /// 從本地文件加載 /// </summary> public virtual void Load() { if (File.Exists(filePath)) { var config = JsonConvert.DeserializeObject<T>(File.ReadAllText(filePath)); foreach (PropertyInfo pro in typeof(T).GetProperties()) { pro.SetValue(this, pro.GetValue(config)); } } } /// <summary> /// 從其它實(shí)例加載 /// </summary> /// <param name="config"></param> public virtual void Load(T config) { foreach (PropertyInfo pro in typeof(T).GetProperties()) { pro.SetValue(this, pro.GetValue(config)); } } /// <summary> /// 從其它實(shí)例加載,僅加載指定的屬性 /// </summary> /// <param name="config"></param> /// <param name="proName"></param> public virtual void Load(T config, IEnumerable<string> proName = null) { foreach (PropertyInfo pro in typeof(T).GetProperties()) { if (proName == null || proName.Contains(pro.Name)) { pro.SetValue(this, pro.GetValue(config)); } } } } }
數(shù)據(jù)綁定基類(lèi) BindableBase
的實(shí)現(xiàn)參考WPF之?dāng)?shù)據(jù)綁定基類(lèi),
代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Runtime.CompilerServices; namespace TestConfigDll { public class BindableBase : INotifyPropertyChanged { /// <summary> /// 屬性值更改時(shí)發(fā)生 /// </summary> public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// 檢查屬性是否已與設(shè)置值相等,設(shè)置屬性并僅在必要時(shí)通知偵聽(tīng)器。 /// </summary> /// <typeparam name="T">屬性的類(lèi)型</typeparam> /// <param name="storage">對(duì)同時(shí)具有g(shù)etter和setter的屬性的引用</param> /// <param name="value">屬性的所需值</param> /// <param name="propertyName">用于通知偵聽(tīng)器的屬性的名稱,此值是可選的,從支持CallerMemberName的編譯器調(diào)用時(shí)可以自動(dòng)提供。</param> /// <returns>如果值已更改,則為T(mén)rue;如果現(xiàn)有值與所需值匹配,則為false。</returns> protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null) { if (EqualityComparer<T>.Default.Equals(storage, value)) return false; storage = value; RaisePropertyChanged(propertyName); return true; } /// <summary> /// 檢查屬性是否已與設(shè)置值相等,設(shè)置屬性并僅在必要時(shí)通知偵聽(tīng)器。 /// </summary> /// <typeparam name="T">屬性的類(lèi)型</typeparam> /// <param name="storage">對(duì)同時(shí)具有g(shù)etter和setter的屬性的引用</param> /// <param name="value">屬性的所需值</param> /// <param name="propertyName">用于通知偵聽(tīng)器的屬性的名稱,此值是可選的,從支持CallerMemberName的編譯器調(diào)用時(shí)可以自動(dòng)提供。</param> /// <param name="onChanged">屬性值更改后調(diào)用的操作。</param> /// <returns>如果值已更改,則為T(mén)rue;如果現(xiàn)有值與所需值匹配,則為false。</returns> protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null) { if (EqualityComparer<T>.Default.Equals(storage, value)) return false; storage = value; onChanged?.Invoke(); RaisePropertyChanged(propertyName); return true; } /// <summary> /// 引發(fā)此對(duì)象的PropertyChanged事件。 /// <param name="propertyName">用于通知偵聽(tīng)器的屬性的名稱,此值是可選的,從支持CallerMemberName的編譯器調(diào)用時(shí)可以自動(dòng)提供。</param> protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } /// <summary> /// 引發(fā)此對(duì)象的PropertyChanged事件。 /// </summary> /// <param name="args">PropertyChangedEventArgs參數(shù)</param> protected virtual void OnPropertyChanged(PropertyChangedEventArgs args) { PropertyChanged?.Invoke(this, args); } } }
3、派生配置類(lèi)
配置類(lèi)的屬性定義不能使用縮寫(xiě)形式,不用單例模式時(shí)可刪除“配置單例”的代碼,
配置類(lèi)代碼如下:
class TestConfig :ConfigBase<TestConfig> { #region 配置單例 /// <summary> /// 唯一實(shí)例 /// </summary> public static TestConfig Instance { get; private set; } = new TestConfig(); /// <summary> /// 靜態(tài)構(gòu)造函數(shù) /// </summary> static TestConfig() { Instance.SetPath("Config\\" + nameof(TestConfig) + ".json"); Instance.Load(); } #endregion #region 屬性定義 private string configStr = ""; public string ConfigStr { get { return this.configStr; } set { SetProperty(ref this.configStr, value); } } private int configInt =0; public int ConfigInt { get { return this.configInt; } set { if (value > 100) { SetProperty(ref this.configInt, value); } } } private bool configBool = false; public bool ConfigBool { get { return this.configBool; } set { SetProperty(ref this.configBool, value); } } #endregion }
4、數(shù)據(jù)綁定
一般數(shù)據(jù)綁定會(huì)定義一個(gè)Model
類(lèi)、ViewModel
類(lèi),本文為了演示方便使用配置類(lèi)同時(shí)承擔(dān)兩者的角色。
4.1 Winform中的數(shù)據(jù)綁定
先設(shè)計(jì)一個(gè)簡(jiǎn)單的界面,如下所示:
配置數(shù)據(jù)的加載、保存不用對(duì)每個(gè)控件進(jìn)行操作,
后臺(tái)代碼如下:
public partial class Form1 : Form { private TestConfig testConfig = new TestConfig(); private List<string> proName = new List<string>(); public Form1() { InitializeComponent(); string textProName = nameof(textBox1.Text); textBox1.DataBindings.Add(textProName, testConfig, nameof(testConfig.ConfigStr)); textBox2.DataBindings.Add(textProName, testConfig, nameof(testConfig.ConfigInt)); string checkedProName= nameof(checkBox1.Checked); checkBox1.DataBindings.Add(checkedProName, testConfig, nameof(testConfig.ConfigBool)); proName.Add(textBox1.DataBindings[0].BindingMemberInfo.BindingField); proName.Add(textBox2.DataBindings[0].BindingMemberInfo.BindingField); proName.Add(checkBox1.DataBindings[0].BindingMemberInfo.BindingField); } private void button1_Click(object sender, EventArgs e) { testConfig.Load(TestConfig.Instance, proName); } private void button2_Click(object sender, EventArgs e) { TestConfig.Instance.Load(testConfig, proName); TestConfig.Instance.Save(); } }
如上所示, testConfig
作為中轉(zhuǎn),可以根據(jù)需求加載、保存配置類(lèi)的部分或全部屬性。如果對(duì)Winform
下的數(shù)據(jù)綁感興趣,可以參考 Winform
普通控件的雙向綁定 。
4.2 WPF下的數(shù)據(jù)綁定
先設(shè)計(jì)一個(gè)簡(jiǎn)單的界面,如下所示:
<Window x:Class="WpfApp1.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:WpfApp1" mc:Ignorable="d" Title="MainWindow" Height="208" Width="306.667"> <Grid> <Label Content="ConfigStr:" HorizontalAlignment="Left" Margin="18,16,0,0" VerticalAlignment="Top"/> <TextBox HorizontalAlignment="Left" Height="23" Margin="113,20,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="156" Text="{Binding Path=ConfigStr ,Mode=TwoWay}"/> <Label Content="ConfigInt:" HorizontalAlignment="Left" Margin="18,44,0,0" VerticalAlignment="Top"/> <TextBox HorizontalAlignment="Left" Height="23" Margin="113,48,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="156" Text="{Binding Path=ConfigInt ,Mode=TwoWay}"/> <Label Content="ConfigBool:" HorizontalAlignment="Left" Margin="18,74,0,0" VerticalAlignment="Top"/> <CheckBox Content="" HorizontalAlignment="Left" Margin="118,84,0,0" VerticalAlignment="Top" IsChecked="{Binding Path=ConfigBool ,Mode=TwoWay}"/> <Button Content="加載" HorizontalAlignment="Left" Margin="24,129,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/> <Button Content="保存" HorizontalAlignment="Left" Margin="194,129,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click_1"/> </Grid> </Window>
相對(duì)于Winform
,WPF
控件綁定的操作由XAML
實(shí)現(xiàn),
后臺(tái)代碼如下:
/// <summary> /// MainWindow.xaml 的交互邏輯 /// </summary> public partial class MainWindow : Window { private TestConfig testConfig = new TestConfig(); public MainWindow() { InitializeComponent(); this.DataContext = testConfig; } private void Button_Click(object sender, RoutedEventArgs e) { testConfig.Load(TestConfig.Instance); } private void Button_Click_1(object sender, RoutedEventArgs e) { TestConfig.Instance.Load(testConfig); TestConfig.Instance.Save(); } }
上面的代碼比較粗糙,沒(méi)有記錄已經(jīng)綁定的屬性,實(shí)際使用時(shí)可以進(jìn)一步優(yōu)化。
到此這篇關(guān)于C#簡(jiǎn)單配置類(lèi)及數(shù)據(jù)綁定的文章就介紹到這了,更多相關(guān)C#簡(jiǎn)單配置類(lèi)及數(shù)據(jù)綁定內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
附件:
- C#配置文件操作類(lèi)分享
- c# 配置文件App.config操作類(lèi)庫(kù)的方法
- C#自定讀取配置文件類(lèi)實(shí)例
- c# NameValueCollection類(lèi)讀取配置信息
- C# TreeView從數(shù)據(jù)庫(kù)綁定數(shù)據(jù)的示例
- C# TextBox數(shù)據(jù)綁定的方法
- C# DataGridView綁定數(shù)據(jù)源的方法
- C#中WPF ListView綁定數(shù)據(jù)的實(shí)例詳解
- C#使用DropDownList綁定添加新數(shù)據(jù)的方法匯總
- C#異步綁定數(shù)據(jù)實(shí)現(xiàn)方法
相關(guān)文章
C#開(kāi)發(fā)微信門(mén)戶及應(yīng)用(1) 微信接口使用
這篇文章主要為大家詳細(xì)介紹了C#開(kāi)發(fā)微信門(mén)戶及應(yīng)用第一篇,微信接口的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06c# 如何實(shí)現(xiàn)獲取二維數(shù)組的列數(shù)
這篇文章主要介紹了c# 實(shí)現(xiàn)獲取二維數(shù)組的列數(shù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04C#安裝OpenCvSharp4的實(shí)現(xiàn)步驟
OpenCv是一款開(kāi)源的圖像處理庫(kù),本文就介紹了C#安裝OpenCvSharp4的實(shí)現(xiàn)步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2022-05-05C#導(dǎo)航器Xpath與XPathNavigator類(lèi)
這篇文章介紹了C#導(dǎo)航器Xpath與XPathNavigator類(lèi),文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì)(3)
這篇文章介紹了C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì),文章主要內(nèi)容是關(guān)于購(gòu)票、座位顏色狀態(tài)的改變及場(chǎng)次座位狀態(tài)的顯示,需要的朋友可以參考下2015-11-11