Winform开发框架之参数配置管理功能实现-基于SettingsProvider.net的构建

在较早时期,我写过一篇文章《结合Control.FirefoxDialog控件,构造优秀的参数配置管理模块》,介绍过在我的Winform框架基础上集成的参数配置模块功能,但是参数模块的配置管理感觉还不够灵活,于是一直在寻找一个较好的替代者,用来结合FireFoxDialog界面一并展现,期间仔细研读过好几篇Codeproject网站上的关于配置管理的文章,但是总是觉得不够灵活或者简便。本文主要针对结合FireFoxDialog参数配置界面组件和SettingsProvider.net技术,实现较为美观、灵活的Winform程序参数配置管理。
在CodeProject上有两三篇文章介绍配置文件的很不错,下面给出链接大家分享下:
http://www.codeproject.com/Articles/25829/User-Settings-Applied
http://www.codeproject.com/Articles/475498/Easier-NET-settings
这两个都很不错,不过感觉不太满足我的简单、高效的需求,偶然之间在GitHub上发现一个《SettingsProvider.net》,做的非常不错,而且感觉扩展性也做的很好,因此就把它和FireFoxDialog界面一同整合,在框架内部实现参数管理功能。

1、SettingsProvider.net功能介绍

这个是在GitHub上的一款参数配置组件,能够基于普通配置文件、ProgramData目录文件、独立存储区文件等方式的配置文件存储,它主要是基于Json格式进行的配置保存,因此我们还可以把它存储到数据库,虽然官方没有提供例子,但是我们很容易通过扩展实现这个功能,后面我介绍我对其数据库参数保存扩展类。
它还可以通过Atrribute标识进行管理配置文件,可以把参数设置为加密、默认值、修改名称等,如下是它的一个配置参数的类的例子。

public class MySettings
{
    [DefaultValue("Jake")]
    [DisplayName("Your Name")]
    public string Name { get; set; }

    [DefaultValue(true)]
    [Description("Should Some App Remember your name?")]
    public bool RememberMe { get;set; }

    public List<Guid> Favourites { get;set; }

    [Key("OriginalName")]
    public string Renamed { get; set; }

    [ProtectedString]
    public string Encrypted { get; set; }
}

读取操作如下所示:

var settingsProvider = new SettingsProvider(); //By default uses IsolatedStorage for storage
var mySettings = settingsProvider.GetSettings<MySettings>();
Assert.True(mySettings.RememberMe); 

保存操作如下所示:

var settingsProvider = new SettingsProvider(); //By default uses IsolatedStorage for storage
var mySettings = new MySettings { Name = "Mr Ginnivan" };
settingsProvider.Save(mySettings);

参数元数据获取操作代码如下:

var settingsProvider = new SettingsProvider();
foreach (var setting in settingsProvider.ReadSettingMetadata<MySettings>())
{
    Console.WriteLine("{0} ({1}) - {2}", setting.DisplayName, setting.Description, setting.DefaultValue);
}

2、参数配置功能界面截图

基于上述的SettingsProvider.net的组件,我们可以结合我前面介绍的FireFoxDialog界面效果,实现较好的参数配置管理功能,如下界面所示。


我们可以分别把不同的参数放到不同的存储介质里面去,如一些常用的,可以配置到本地目录文件里面去,一些和个人信息相关的内容,我们可以把它放到数据库里面去,这样可以在各个客户端使用都不需要重新配置,非常方便。
上面的例子,我针对性介绍两个,一个是基于本地文件参数存储,一个是基于数据库文件的参数存储。

3、基于SettingsProvider.net的整合操作的实现

介绍了基于SettingsProvider.net的功能,以及最终整合的效果,我们来看看它具体是如何整合实现不同文件类型数据的保存的。
首先,我们在设计模式下,拖动好对应的界面,由于FireFoxDialog界面本来就是用来做参数设置的,因此他们里面有一些控件就不一一介绍了,具体可以参考对应的文章(http://www.codeproject.com/KB/miscctrl/ControlFirefoxDialog.aspx?msg=1856449)。
我们看看上述效果界面的设计界面和后台代码。
设计界面就是如下所示,拖动一个参数配置用户控件到窗体上,设置好对应的内容就可以了。


后台代码如下所示。

    public partial class FrmSettings : BaseForm
    {
        public FrmSettings()
        {
            InitializeComponent();
        }

        private void FrmSettings_Load(object sender, EventArgs e)
        {
            this.firefoxDialog1.ImageList = this.imageList1;

            this.firefoxDialog1.AddPage("报表设置", new PageReport());//基于本地文件的参数存储
            this.firefoxDialog1.AddPage("邮箱设置", new PageEmail());//基于数据库的参数存储

            //下面是陪衬的
            this.firefoxDialog1.AddPage("短信设置", new PageEmail());
            this.firefoxDialog1.AddPage("声音设置", new PageEmail());
            this.firefoxDialog1.AddPage("系统设置", new PageEmail());
            this.firefoxDialog1.AddPage("备份设置", new PageEmail());
            this.firefoxDialog1.AddPage("其他设置", new PageEmail());

            this.firefoxDialog1.Init();
        }
    }

这里最有代表性的是PageReport和PageEmail两个组件对象。

1)报表模块配置管理

基于报表参数和邮件参数,我们可以定义一个参数对象类,用来方便保存和获取数据的承载对象。

报表参数对象类如下(只做了简单的一个报表路径处理):

    /// <summary>
    /// 报表设置
    /// </summary>
    public class ReportParameter
    {
        /// <summary>
        /// 派车单报表文件
        /// </summary>
        [DefaultValue("WHC.CarDispatch.CarSendBill2.rdlc")]
        public string CarSendReportFile { get; set; }
    }

对应的设计界面如下所示,用来提供一个报表文件的参数配置,很简单了。



我们来看看后台的组件,对参数是如何保存和显示的。
首先需要初始化相应的对象,我们这里使用了在程序运行目录下,创建一个文件用来保存这些设置。

public partial class PageReport : PropertyPage
{
    private SettingsProvider settings;
    private ISettingsStorage store;

    public PageReport()
    {
        InitializeComponent();

        if(!this.DesignMode)
        {
            // PortableStorage: 在运行程序目录创建一个setting的文件记录参数数据
            store = new PortableStorage();
            settings = new SettingsProvider(store);
        }
    }

注意:PortableStorage是在运行程序目录创建一个setting的文件记录参数数据,运行后,最终会在目录下生成一个类似“ReportParameter.settings”的文件,它的内容格式如下所示。

[{"Key":"CarSendReportFile","Value":"\"WHC.CarDispatch.CarSendBill2.rdlc\""}]

我们看看报表组件的参数是如何初始化的:

public override void OnInit()
{
    ReportParameter parameter = settings.GetSettings<ReportParameter>();
    if (parameter != null)
    {
        EnableOtherReport(false);
        string reportFile = parameter.CarSendReportFile;
        if (reportFile == "WHC.CarDispatch.CarSendBill2.rdlc")
        {
            this.radReport.SelectedIndex = 0;                    
        }
        else if (reportFile == "WHC.CarDispatch.CarSendBill.rdlc")
        {
            this.radReport.SelectedIndex = 1;
        }
        else
        {
            EnableOtherReport(true);
            this.radReport.SelectedIndex = 2;
            this.txtOtherReport.Text = reportFile;
        }
    }
}

通过参数的存储对象处理,这样我们就可以通过ReportParameter 进行数据获取了。

保存参数的时候,同样也是先获取到一个参数对象,并设置它的值后,然后进行保存就可以了,具体代码如下所示。

public override bool OnApply()
{
    bool result = false;
    try
    {
        ReportParameter parameter = settings.GetSettings<ReportParameter>();
        if (parameter != null)
        {                    
            int otherType = 2;//2代表其他类型
            if (this.radReport.SelectedIndex < otherType)
            {
                parameter.CarSendReportFile = this.radReport.Properties.Items[this.radReport.SelectedIndex].Value.ToString();
            }
            else
            {
                parameter.CarSendReportFile = this.txtOtherReport.Text;
            }
            settings.SaveSettings<ReportParameter>(parameter);
        }
        result = true;
    }
    catch (Exception ex)
    {
        LogTextHelper.Error(ex);
        MessageDxUtil.ShowError(ex.Message);
    }

    return result;
}

2)邮件参数配置管理

邮件参数对象类如下:

/// <summary>
/// 邮箱设置
/// </summary>
public class EmailParameter
{
    /// <summary>
    /// 邮件账号
    /// </summary>
    //[DefaultValue("wuhuacong@163.com")]
    public string Email { get; set; }

    /// <summary>
    /// POP3服务器
    /// </summary>
    [DefaultValue("pop.163.com")]
    public string Pop3Server { get; set; }

    /// <summary>
    /// POP3端口
    /// </summary>
    [DefaultValue(110)]
    public int Pop3Port { get; set; }

    /// <summary>
    /// SMTP服务器
    /// </summary>
    [DefaultValue("smtp.163.com")]
    public string SmtpServer { get; set; }

    /// <summary>
    /// SMTP端口
    /// </summary>
    [DefaultValue(25)]
    public int SmtpPort { get; set; }

    /// <summary>
    /// 登陆账号
    /// </summary>
    public string LoginId { get; set; }

    /// <summary>
    /// 登陆密码
    /// </summary>
    [ProtectedString]
    public string Password { get; set; }

    /// <summary>
    /// 使用SSL加密
    /// </summary>
    [DefaultValue(false)]
    public bool UseSSL { get; set; }
}

参数显示和保存的界面设计如下所示。



界面的初始化,同样和上面的差不多,不过这里使用了数据库的存储类DatabaseStorage,内容将保存在数据库里面,而且我们通过用户的标识Create进行路径的针对性处理,可以使每个用户的配置文件不同。

public partial class PageEmail : PropertyPage
{
    private SettingsProvider settings;
    private ISettingsStorage store;

    public PageEmail()
    {
        InitializeComponent();

        if (!this.DesignMode)
        {
            //DatabaseStorage:在数据库里面,以指定用户标识保存参数数据
            string creator = Portal.gc.LoginUserInfo.Name;
            store = new DatabaseStorage(creator);
            settings = new SettingsProvider(store);
        }
    }

参数的加载代码如下所示,也就是把数据获取后,显示在界面上即可。

public override void OnInit()
{
    EmailParameter parameter = settings.GetSettings<EmailParameter>();
    if (parameter != null)
    {
        this.txtEmail.Text = parameter.Email;
        this.txtLoginId.Text = parameter.LoginId;
        this.txtPassword.Text = parameter.Password;
        this.txtPassword.Tag = parameter.Password;
        this.txtPop3Port.Value = parameter.Pop3Port;
        this.txtPop3Server.Text = parameter.Pop3Server;
        this.txtSmtpPort.Value = parameter.SmtpPort;
        this.txtSmtpServer.Text = parameter.SmtpServer;
        this.txtUseSSL.Checked = parameter.UseSSL;
    }
}

数据的保存操作也很简单,和前面的操作差不多,如下所示。

EmailParameter parameter = settings.GetSettings<EmailParameter>();
if (parameter != null)
{                    
    parameter.Email = this.txtEmail.Text;
    parameter.LoginId = this.txtLoginId.Text;
    parameter.Password = this.txtPassword.Text;
    parameter.Pop3Port = Convert.ToInt32(this.txtPop3Port.Value);
    parameter.Pop3Server = this.txtPop3Server.Text;
    parameter.SmtpPort = Convert.ToInt32(this.txtSmtpPort.Value);
    parameter.SmtpServer = this.txtSmtpServer.Text;
    parameter.UseSSL = this.txtUseSSL.Checked;

    settings.SaveSettings<EmailParameter>(parameter);
}

最终,我们在数据库表里面,可以看到对应记录已经保存起来了,并且用户密码部分也进行了加密处理。



这样,我们整合两者的特点,就可以实现比较不错的参数配置界面的显示和后台存储处理了,针对性的,使用不同的存储介质,以满足不同的需要。


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容