首页 > 代码库 > 【.net 深呼吸】自己动手来写应用程序设置类

【.net 深呼吸】自己动手来写应用程序设置类

在开始装逼之前,老周先说明一件事。有人说老周写的东西太简单了,能不能写点复杂点。这问题就来了,要写什么东西才叫“复杂”?最重要的是,写得太复杂了,一方面很多朋友看不懂,另一方面,连老周自己也不知道怎么表述。

而且,老周也不能把以前在K公司、Z公司和T公司中做项目的东西写出来的,其实嘛,工作中的编程没什么可写的,无非就是 select、insert、delete、update,无非就是连接数据库,断开连接,同步一下数据,把数据变成XML或JSON再发给另一终端。无非就是读读你的网卡CPU硬盘序列号,组成个东东再加密,计算一下授权码,又或者生成个假冒伪劣证书给用户授授权。再不是就写几个API给别人调几下。让脑细胞死亡率大增的,就是要动态生成计算工资的公式,这个嘛,当时老周是选用 Code Dom 来生成的,代码生成这玩意儿,老周前些时间就写过好些博文了,相信大伙伴们也看过了。

所以,你看,工作中用到的东西其实很片面很单一,所覆盖的面还不如老周平时闲着没事的时候写的小程序。故,还是写点简单的东西和谐一点,你懂我懂他也懂,岂不甚妙,人活着为啥老跟自己过不去呢,姜育恒大哥就曾经唱过:

  • 不管明天要面对多少伤痛和迷惑
  • 曾经在幽幽暗暗反反复复中追问
  • 才知道平平淡淡从从容容是最真

平淡是福,简单是乐,谁谓不然?

 

好了,上面的鬼话说完了,下面咱们开始说人话。

我们都知道,VS 开发环境会为项目自动生成一个settings类,即用于访问应用程序设置的帮助类,数据是存到跟应用程序一起的 config 文件中,比如历史上著名的 App.config 文件。

顺便提一下,VS 自动生成的应用设置类有一个特点:基于应用程序范围的设置项是只读的,基于用户范围的设置项是可读可写的。看不懂?没事,你可以动手调戏一下这个settings类的。

技术分享

在Properties节点下,你应该能看到一个 Settings 文件,然后打开它。

技术分享

这里你可以自己添加设置项,注意看“范围”这一列,它就两个选项,要么是基于应用范围,要么基于用户范围。好,我们为每个范围各添加一个设置项。

技术分享

随后,我们保存一下(必须,保存才会生成代码),接着打开代码,看看设计器生成的 Settings 类。

技术分享

 

 代码选段。

        [global::System.Configuration.UserScopedSettingAttribute()]        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]        [global::System.Configuration.DefaultSettingValueAttribute("0")]        public byte TestV1 {            get {                return ((byte)(this["TestV1"]));            }            set {                this["TestV1"] = value;            }        }                [global::System.Configuration.ApplicationScopedSettingAttribute()]        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]        [global::System.Configuration.DefaultSettingValueAttribute("0")]        public int TestV2 {            get {                return ((int)(this["TestV2"]));            }        }

在属性上应用 ApplicationScopedSettingAttribute 表示该设置项是应用程序范围的,大伙看到,属性中只有 get 没有 set,说明它是只读的。而应用了 UserScopedSettingAttribute 的属性表示的是用户范围内的设置项,此时看到该属性同时有 get 和 set ,即可读可写。

为什么应用程序范围的设置项相关属性会生成只读属性呢,后来一看MSDN就明白了,因为当调用相关方法保存设置时,应用程序范围内的设置是不会起作用的,但是不会报错。也就是说,要自己写可以直接保存的设置项,只能把属性定义为用户范围内的

 

如果觉得生成的设置类不好玩,我们可以自己写的。

编写这个类其实很简单,我们只需从 ApplicationSettingsBase 类派生即可,该类位于 System.Configuration 命名空间下,它是一个抽象类。在写自定义的应用设置类时,我们可以像普通类一样公开属性,这样读写设置项时也方便,而且,你还可以直接用于数据绑定。

在包装属性时,是通过调用基类的索引器来存取内容的,它是一个字典模型,key是字符串类型,而value是Object类型,这样你可以设置各种类型的值。

好,咱们写一个来表演一下。

    internal class AppSettings : ApplicationSettingsBase    {        #region 常量        const string APP_TITLE = "appTitle";        const string APP_USAGE = "appUsage";        const string USER_NAME = "userName";        const string USE_YEARS = "useYears";        #endregion        [UserScopedSetting]        [DefaultSettingValue("my app")]        public string AppTitle        {            set            {                this[APP_TITLE] = value;            }            get { return (string)this[APP_TITLE]; }        }        [UserScopedSetting]        [DefaultSettingValue("用于装X")]        public string AppUsage        {            get { return (string)this[APP_USAGE]; }            set { this[APP_USAGE] = value; }        }        [UserScopedSetting]        [DefaultSettingValue("大傻冬")]        public string UserName        {            get { return (string)this[USER_NAME]; }            set { this[USER_NAME] = value; }        }        [UserScopedSetting]        [DefaultSettingValue("3")]        public int UseYears        {            get { return (int)this[USE_YEARS]; }            set { this[USE_YEARS] = value; }        }    }

由于属性实现中使用的key是字符串类型的,为了防止多次输入时出现错误,通常可以预先声明一组字符串常量。

        const string APP_TITLE = "appTitle";        const string APP_USAGE = "appUsage";        const string USER_NAME = "userName";        const string USE_YEARS = "useYears";

 

在类公开的属性上除了应用表示用户范围内的标识特性外,还应用了 DefaultSettingValue 特性,它用来设置项的默认值,值是以字符串形式表示的。

 

这个示范的设置类包装了四个设置项,那么,怎么耍呢。耍起来也很简单,跟耍猴差不多。首先,你要new一个类实例,接着就可以通过我们刚才包装的那四个属性来读写设置项,最后,调用 Save 方法,就可以把修改后的数据保存到配置文件中。

 

让设置类与用户界面交互,最简单最方便的方法是使用绑定,比如这样。

        <TextBox Grid.Column="1" Text="{Binding Path=AppTitle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>        <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding Path=AppUsage,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>        <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Path=UserName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>        <TextBox Grid.Column="1" Grid.Row="3" Text="{Binding Path=UseYears,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>

 

这个设置类是可以进行双向绑定的,因为基类 ApplicationSettingsBase 实现了 INotifyPropertyChanged 接口。通常我们可以在窗口关闭时保存配置。

        protected override void OnClosing(CancelEventArgs e)        {            base.OnClosing(e);            settings.Save();        }

 

以前我们开发程序,都习惯在界面上放一个保存按钮,当用户点击后保存,不过现在好像流行了,因为用户修改完设置后还要点一按钮来保存,操作有点复杂,让窗口在关闭时自动保存设置,显得更友好。

那么,这个破文件到底保存到哪里去了,在应用所在目录中的配置文件中并没有。应用目录中的配置文件存的应用程序级别的设置,用户级别的配置应该与当前用户的私人目录有关。

打开文件管理器,在地址栏中输入:%UserProfile%\AppData\Local,然后回车,就会进入当前用户文件夹下的appData的Local子目录,然后,在这个目录下,你会看到一个以你的应用程序命名的文件夹,然后你继续进入子目录,直到看到一个名为 user.config 的文件。对,就是它了,不信你打开看看。

<configuration>    <configSections>        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >            <section name="DemoApp.AppSettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />        </sectionGroup>    </configSections>    <userSettings>        <DemoApp.AppSettings>            <setting name="UseYears" serializeAs="String">                <value>2</value>            </setting>            <setting name="UserName" serializeAs="String">                <value>矮冬瓜</value>            </setting>            <setting name="AppUsage" serializeAs="String">                <value>用于忽悠未成年人</value>            </setting>            <setting name="AppTitle" serializeAs="String">                <value>天国第一假货</value>            </setting>        </DemoApp.AppSettings>    </userSettings></configuration>

 

另外,ApplicationSettingsBase 类有几个事件比较有用,必要时可以用上。当设置数加载后会发生 SettingsLoaded 事件,从名字中也能知道其用途;在设置项被修改之前,会发生 SettingChanging 事件,修改之后会发生 PropertyChanged 事件(实现了INotifyPropertyChanged接口);当调用 Save 方法保存之前,会引发 SettingsSaving 事件,事件参数会包含一个 Cancel 属性,如果想取消保存,可以将该属性设置为 true。

 

示例源代码下载地址:请点击?这里?

 

【.net 深呼吸】自己动手来写应用程序设置类