C#簡(jiǎn)單配置類及數(shù)據(jù)綁定
1、簡(jiǎn)介
本文實(shí)現(xiàn)一個(gè)簡(jiǎn)單的配置類,原理比較簡(jiǎn)單,適用于一些小型項(xiàng)目。主要實(shí)現(xiàn)以下功能:
- 保存配置到
json文件 - 從文件或?qū)嵗虞d配置類的屬性值
- 數(shù)據(jù)綁定到界面控件
一般情況下,項(xiàng)目都會(huì)提供配置的設(shè)置界面,很少手動(dòng)更改配置文件,所以選擇以json文件保存配置數(shù)據(jù)。
2、配置基類
為了方便管理,項(xiàng)目中的配置一般是按用途劃分到不同的配置類中,保存時(shí)也是保存到多個(gè)配置文件。所以,我們需要實(shí)現(xiàn)一個(gè)配置基類,然后再派生出不同用途的配置類。
配置基類需要引用 Json.NET ,繼承數(shù)據(jù)綁定基類 BindableBase ,實(shí)現(xiàn)從其它實(shí)例加載數(shù)據(jù)的功能
基類代碼如下:
using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
namespace TestConfigDll
{
/// <summary>
/// 配置基類,實(shí)現(xiàn)配置類的加載、保存功能
/// </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ù)綁定基類 BindableBase 的實(shí)現(xiàn)參考WPF之?dāng)?shù)據(jù)綁定基類,
代碼如下:
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í)通知偵聽器。
/// </summary>
/// <typeparam name="T">屬性的類型</typeparam>
/// <param name="storage">對(duì)同時(shí)具有g(shù)etter和setter的屬性的引用</param>
/// <param name="value">屬性的所需值</param>
/// <param name="propertyName">用于通知偵聽器的屬性的名稱,此值是可選的,從支持CallerMemberName的編譯器調(diào)用時(shí)可以自動(dòng)提供。</param>
/// <returns>如果值已更改,則為True;如果現(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í)通知偵聽器。
/// </summary>
/// <typeparam name="T">屬性的類型</typeparam>
/// <param name="storage">對(duì)同時(shí)具有g(shù)etter和setter的屬性的引用</param>
/// <param name="value">屬性的所需值</param>
/// <param name="propertyName">用于通知偵聽器的屬性的名稱,此值是可選的,從支持CallerMemberName的編譯器調(diào)用時(shí)可以自動(dòng)提供。</param>
/// <param name="onChanged">屬性值更改后調(diào)用的操作。</param>
/// <returns>如果值已更改,則為True;如果現(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">用于通知偵聽器的屬性的名稱,此值是可選的,從支持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、派生配置類
配置類的屬性定義不能使用縮寫形式,不用單例模式時(shí)可刪除“配置單例”的代碼,
配置類代碼如下:
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類、ViewModel類,本文為了演示方便使用配置類同時(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ù)需求加載、保存配置類的部分或全部屬性。如果對(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();
}
}
上面的代碼比較粗糙,沒有記錄已經(jīng)綁定的屬性,實(shí)際使用時(shí)可以進(jìn)一步優(yōu)化。
到此這篇關(guān)于C#簡(jiǎn)單配置類及數(shù)據(jù)綁定的文章就介紹到這了,更多相關(guān)C#簡(jiǎn)單配置類及數(shù)據(jù)綁定內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
附件:
相關(guān)文章
C#開發(fā)微信門戶及應(yīng)用(1) 微信接口使用
這篇文章主要為大家詳細(xì)介紹了C#開發(fā)微信門戶及應(yīng)用第一篇,微信接口的使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
c# 如何實(shí)現(xiàn)獲取二維數(shù)組的列數(shù)
這篇文章主要介紹了c# 實(shí)現(xiàn)獲取二維數(shù)組的列數(shù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-04-04
C#安裝OpenCvSharp4的實(shí)現(xiàn)步驟
OpenCv是一款開源的圖像處理庫,本文就介紹了C#安裝OpenCvSharp4的實(shí)現(xiàn)步驟,具有一定的參考價(jià)值,感興趣的可以了解一下2022-05-05
C#導(dǎo)航器Xpath與XPathNavigator類
這篇文章介紹了C#導(dǎo)航器Xpath與XPathNavigator類,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì)(3)
這篇文章介紹了C#影院售票系統(tǒng)畢業(yè)設(shè)計(jì),文章主要內(nèi)容是關(guān)于購票、座位顏色狀態(tài)的改變及場(chǎng)次座位狀態(tài)的顯示,需要的朋友可以參考下2015-11-11

