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

而且,老周也不能把以前在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("")]
public byte TestV1 {
get {
return ((byte)(this["TestV1"]));
}
set {
this["TestV1"] = value;
}
} [global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
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("")]
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="" Text="{Binding Path=AppTitle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Column="" Grid.Row="" Text="{Binding Path=AppUsage,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Column="" Grid.Row="" Text="{Binding Path=UserName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Column="" Grid.Row="" 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 深呼吸】自己动手来写应用程序设置类的更多相关文章

  1. 使用Code::blocks在windows下写网络程序

    使用Code::blocks在windows下写网络程序 作者 He YiJun – storysnail<at>gmail.com 团队 ls 版权 转载请保留本声明! 本文档包含的原创 ...

  2. JAVA-集合作业-已知有十六支男子足球队参加2008 北京奥运会。写一个程序,把这16 支球队随机分为4 个组。采用List集合和随机数

    第二题 已知有十六支男子足球队参加2008 北京奥运会.写一个程序,把这16 支球队随机分为4 个组.采用List集合和随机数 2008 北京奥运会男足参赛国家: 科特迪瓦,阿根廷,澳大利亚,塞尔维亚 ...

  3. PIC12F629帮我用C语言写个程序,控制三个LED亮灭

    http://power.baidu.com/question/240873584599025684.html?entry=browse_difficult PIC12F629帮我用C语言写个程序,控 ...

  4. 学了C语言,如何写个程序计算出每个月的第一个星期一对应的日期

    在前面,我们分别利用泰勒公式和C标准库中的mktime()函数推算了某个特定日期所对应的星期几,刚做完这些,就又遇到了一个与日期相关的新任务: 老板把每个月例会的时间定在了每个月的第一个星期一,他让我 ...

  5. 用C语言写个程序推算出是星期几?(用泰勒公式实现)

    在日常生活中,我们常常遇到要知道某一天是星期几的问题.有时候,我们还想知道历史上某一天是星期几.比如: “你出生的那一天是星期几啊?” “明年五一是不是星期天?我去找你玩?” 通常,解决这个问题的最简 ...

  6. hadoop-初学者写map-reduce程序中容易出现的问题 3

    1.写hadoop的map-reduce程序之前所必须知道的基础知识: 1)hadoop map-reduce的自带的数据类型: Hadoop提供了如下内容的数据类型,这些数据类型都实现了Writab ...

  7. 【百度地图-安卓SDK】从头开始写android程序

    [百度地图-安卓SDK]从头开始写android程序首先确保有这四个文件    安装jdk先安装android开发SDK(并不只是为eclipse服务的),即运行installer_r15-windo ...

  8. 写Java程序要体现面向对象

          对于之前写的一篇文章现在想想存在不足之处,之前写的测试ArrayList和LinkedList的各项操作性能比较的程序没有体现面向对象的封装特性,所以,今天把代码重新写了一遍,其实改动的地 ...

  9. 教你用shell写CGI程序

    以前用shell写过一些cgi的例子.今天向大家介绍一下. CGI是一种接口的标准,并不区分编程语言,也就是说,CGI可以用任何一种语言编写,只要这种语言具有标准输入.输出和环境变量.CGI会将标准输 ...

随机推荐

  1. Docker化tomcat 并且使用maven热部署

    今天没事干 就把自己的tomcat  docker化并且使用maven实现热部署 特别记录一下~ 1.首先进行centos7的安装 就不在记录了 注意的是最好使用centos7 因为docker 依赖 ...

  2. 关于sqlmap的一些命令

    Options(选项):--version 显示程序的版本号并退出-h, --help 显示此帮助消息并退出-v VERBOSE 详细级别:0-6(默认为1)Target(目标):以下至少需要设置其中 ...

  3. MySQL分页优化中的“INNER JOIN方式优化分页算法”到底在什么情况下会生效?

    本文出处:http://www.cnblogs.com/wy123/p/7003157.html 最近无意间看到一个MySQL分页优化的测试案例,并没有非常具体地说明测试场景的情况下,给出了一种经典的 ...

  4. 通过数据,修改金蝶ERP的收料通知单不合格和合格数量,修改生产投料单,委外发出数量

    update POInStockEntry set FAuxNotPassQty=不合格数量 where FInterID=(select FInterID from POInStock where ...

  5. go 基础语法

    时间有限,简单记一些常用的,麻烦的不写了 定义变量:可以连续定义,也可以单个定义 var a int    int类型 var a="ds"   默认string类型 a:=&qu ...

  6. oracle表的简单操作

    版权声明:本文为博主原创文章,转载时请注明原文链接. 1.创建表 ) ) not null,primary key(num)); 创建了一个两个字段的表,num和name,都设置为非空,num设为主键 ...

  7. Compare and Swap [CAS] 算法

    一个Java 5中最好的补充是对原子操作的支持类,如AtomicInteger,AtomicLong等.这些类帮助你减少复杂的(不必要的)多线程代码,实际上只是完成一些基本操作,如增加或减少多个线程之 ...

  8. python 标准库 -- os

    os os.getcwd() os.getcwd() # 获取当前工作目录 os.listdir(path) os.listdir('/tmp') # 列出指定目录下的文件和目录 os.mkdir(p ...

  9. [css 实践篇] CSS box-orient

    定义和用法 box-orient 属性规定框的子元素应该被水平或垂直排列. 提示:水平框中的子元素从左向右进行显示,而垂直框的子元素从上向下进行显示.不过,box-direction 和 box-or ...

  10. PHP基础入门(四)---PHP数组实用基础知识

    PHP数组 数组是特殊的变量,它可以同时保存一个以上的值. ***关键词:数组基础.数组遍历.超全局数组.数组功能.数组函数. 下面来和大家分享一下有关PHP的数组基础知识,希望对你PHP的学习有所帮 ...