iFolder是一个文件共享的解决方案,原来是Novell公司的一个很重要的产品,现在Novell已经打算将它开放源码,并且使用.Net技术将它重写一遍,使它可以跨平台的运行在WINDOWS,LINUX,MacOS上.
为什么Novell不选择其它的跨平台技术,比如JAVA呢?这是一个很有意思的话题,而且看来Novell公司也很乐意谈论它,他们正准备出一份白皮书来专门说明这个问题.
windows和Linux平台下的Dotnet技术
iFolder是一个文件共享的解决方案,原来是Novell公司的一个很重要的产品,现在Novell已经打算将它开放源码,并且使用.Net技术将它重写一遍,使它可以跨平台的运行在WINDOWS,LINUX,MacOS上.
为什么Novell不选择其它的跨平台技术,比如JAVA呢?这是一个很有意思的话题,而且看来Novell公司也很乐意谈论它,他们正准备出一份白皮书来专门说明这个问题.
1.BZip2
加入ICSharpCode.SharpZipLib.dll的引用,在#Develop的安装目录下的\SharpDevelop\bin目录下。然后在程序中使用using语句把BZip2类库包含进来。
压缩:使用BZip2的静态方法Compress。
它的第一个参数是所要压缩的文件所代表的输入流,可以使用System.IO.File的静态方法OpenRead。
第二个参数是要建立的压缩文件所代表的输出流,可以使用System.IO.File的静态方法Create创建,压缩文件名是所要压缩文件的文件名加上压缩后缀.bz(同样你也可以取其他的文件名)。
第三个参数是要压缩的块大小(一般为2048的整数)。
解压:使用BZip2的静态方法Decompress。
它的第一个参数是所要解压的压缩文件所代表的输入流,可以使用System.IO.File的静态方法OpenRead。
第二个参数是要建立的解压文件所代表的输出流,可以使用System.IO.File的静态方法Create创建,因为解压文件的文件名是去掉了压缩文件扩展名的压缩文件名(你也可以做成解压文件与压缩文件不同名的)。
编译你的程序,然后在命令行方式下输入bzip2 文件名(假设建立的C#文件是bzip2,就可以生成压缩文件;输入bzip2 -d 文件名,就会解压出文件来(-d是用来表示解压,你也可以使用其他的符号)。
呵呵,原来做压缩可以这么简单的,压缩效果也可以啊。
using System;
using System.IO;
using ICSharpCode.SharpZipLib.BZip2;
class MainClass
{
public static void Main(string[] args)
{
if (args[0] == ”-d”) { // 解压
BZip2.Decompress(File.OpenRead(args[1]), File.Create(Path.GetFileNameWithoutExtension(args[1])));
} else { //压缩
BZip2.Compress(File.OpenRead(args[0]), File.Create(args[0] + ”.bz”), 4096);
}
}
}
2.GZip
加入ICSharpCode.SharpZipLib.dll的引用,在#Develop的安装目录下的\SharpDevelop\bin目录下。然后在程序中使用using语句把GZip类库包含进来。
由于GZip没有BZip2的简单解压缩方法,因此只能使用流方法来进行解压缩。具体的方法见程序的说明。
编译程序,然后在命令行方式下输入GZip 文件名(假设建立的C#文件是GZip,就可以生成压缩文件;输入GZip -d 文件名,就会解压出文件来(-d是用来表示解压,你也可以使用其他的符号)。
using System;
using System.IO;
using ICSharpCode.SharpZipLib.GZip;
class MainClass
{
public static void Main(string[] args)
{
if (args[0] == ”-d”) { // 解压
Stream s = new GZipInputStream(File.OpenRead(args[1]));
//生成一个GZipInputStream流,用来打开压缩文件。
//因为GZipInputStream由Stream派生,所以它可以赋给Stream。
//它的构造函数的参数是一个表示要解压的压缩文件所代表的文件流
FileStream fs = File.Create(Path.GetFileNameWithoutExtension(args[1]));
//生成一个文件流,它用来生成解压文件
//可以使用System.IO.File的静态函数Create来生成文件流
int size = 2048;//指定压缩块的大小,一般为2048的倍数
byte[] writeData = new byte[size];//指定缓冲区的大小
while (true) {
size = s.Read(writeData, 0, size);//读入一个压缩块
if (size > 0) {
fs.Write(writeData, 0, size);//写入解压文件代表的文件流
} else {
break;//若读到压缩文件尾,则结束
}
}
s.Close();
} else { //压缩 Stream s = new GZipOutputStream(File.Create(args[0] + ”.gz”));
//生成一个GZipOutputStream流,用来生成压缩文件。
//因为GZipOutputStream由Stream派生,所以它可以赋给Stream。
FileStream fs = File.OpenRead(args[0]);
/生成一个文件流,它用来打开要压缩的文件
//可以使用System.IO.File的静态函数OpenRead来生成文件流
byte[] writeData = new byte[fs.Length];
//指定缓冲区的大小
fs.Read(writeData, 0, (int)fs.Length);
//读入文件
s.Write(writeData, 0, writeData.Length);
//写入压缩文件
s.Close();
//关闭文件
}
}
}
利用SharpZipLib实现实时zip压缩下载整个目录
要下载整个目录,一般方法是一个个文家下载或ftp工具
现在用SharpZipLib就能实现实时zip压缩下载整个目录
SharpZipLib提供了多种压缩算法的支持,纯csharp代码,参见
http://www.icsharpcode.net/OpenSource/SharpZipLib/default.asp
原理是通过递归方法将每个文件压缩到ZipOutputStream,然后下载
代码和范例如下:
<%@ Import namespace=”ICSharpCode.SharpZipLib.Zip” %>
<%@ Import Namespace=”System.IO” %>
<script language=”c#” runat=”server”>
ZipOutputStream zos=null;
String strBaseDir=”";
void dlZipDir(string strPath,string strFileName){
MemoryStream ms =null;
Response.ContentType = ”application/octet-stream”;
strFileName=HttpUtility.UrlEncode(strFileName).Replace(‘+’,' ’);
Response.AddHeader(“Content-Disposition”, ”attachment; filename=” + strFileName+”.zip”);
ms = new MemoryStream();
zos = new ZipOutputStream(ms);
strBaseDir=strPath+”\\”;
addZipEntry(strBaseDir);
zos.Finish();
zos.Close();
Response.Clear();
Response.BinaryWrite(ms.ToArray());
Response.End();
}
void addZipEntry(string PathStr){
DirectoryInfo di= new DirectoryInfo(PathStr);
foreach(DirectoryInfo item in di.GetDirectories()){
addZipEntry(item.FullName);
}
foreach(FileInfo item in di.GetFiles()){
FileStream fs = File.OpenRead(item.FullName);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
string strEntryName=item.FullName.Replace(strBaseDir,”");
ZipEntry entry = new ZipEntry(strEntryName);
zos.PutNextEntry(entry);
zos.Write(buffer, 0, buffer.Length);
fs.Close();
}
}
void Page_Load(){
dlZipDir(Server.MapPath(“.”),”test”);
}
</script>
在.net的世界中C#也提供了和java中“文档注释”相同的功能。如果结合相应的工具,它还可以为我们产生漂亮的WEB风格的文档。
文档自动化初步:
在C#中文档注释对应的符号是:///。但光使用它还是不能为我们产生代码文档,还必须使用特殊的标记才行。这些标记实际上是XML标记,最常用的是< summary >。例如:
/// <summary>
/// A method with a string array param.
/// </summary>
public void Koo(string[] ss) {}
但是,并不是所有使用文档注释和这些标记的地方编译器都会为我们生成文档,它还会看这些标记是否与一些代码结构相关联。例如:
/// <summary>
/// 不产生这行
/// </summary>
就不产生任何文档。这些代码结构必须是:class, struct, enum, method, property, field, indexer, delegate, 或event.
- 命令行:csc /doc: ….xml …..cs;
- 如使用VS.net,则:项目 -> 属性 -> 配置属性 -> 生成 -> 输出 -> xml文档文件(在此填写文件名和路径);
- 如要生成web注释:工具 ->生成注释 web……。
字符 | 描述 |
N | Namespace |
T | 类型:class, interface, struct, enum, delegate |
F | Field |
P | Property (包括indexers or other indexed properties) |
M | Method (包括constructors和operators) |
E | Event |
! | Error:编译器无法解析这个元素。 |
一个输出的文件注释的示例:
<member name=”F:SimpleXML.Class1.h”>
<summary>
An enum field.
</summary>
</member>
<member name=”T:SimpleXML.Class1.hType”>
<summary>
An enum type.
</summary>
</member>
标记 | 描述 |
<c> | 指示这行注释标识为Code |
<code> | 指示多行注释标识为Code |
<example> | 经常与<code>连用,用来给出如何使用某些成员的例子。 |
<exception> | 指明一个成员会抛出哪些异常,经常与cref属性连用。 |
<include> | 指明注释在哪些文件中,以及位置。 |
<list> | 用来定义表头,经常与<item>连用 |
<newpara> | 内部使用,如<remarks>或<returns>。让用户有机会给注释文本加入其他的结构。 |
<param> | 说明参数的属性,编译器会检查参数的合法性。如果通不过,会在文档中产生!标识的警告。 |
<paramref> | 类似<param>。 |
<permission> | 标明用于成员的代码存取的安全性。 |
<remarks> | 用于描述class或其它类型的描述性文字,不涉及具体细节(如果是这样,使用<summary>)。 |
<returns> | 描述方法或函数的返回值。 |
<see> | 指定一个链接。 |
<seealso> | 指定要出现在See Also部分的文本。 |
<summary> | 类型的描述性文字。它会被vs.net内置的IntelliSense使用并显示在对应的类型中。(即在vs.net中击键“.”出现的提示) |
<value> | 描述属性。 |
以上标记的属性。
标记 | 描述 |
cref | 可用于任何标记来提供一个代码元素的参考。编译器将检查这个代码元素是否存在,如不存在则在文档中用!标识。 |
name | 用于<param>或<paramref> |
标记使用的例子
1. <param>标记:函数文档化一个参数。<parm>标记使用一个属性name,它的值明明正在文档编制的参数
/// <summary>
/// A method with a string array param.
/// </summary>
/// <param name=”ss”></param>
public void Koo(string[] ss) {}
2. <returns>标记:表述函数的返回值,不带属性,该标记的文本包含返回值信息
/// <summary>
/// A nonvoid method.
/// </summary>
/// <returns>The result of the operation.</returns>
public int Noo() { return 0; }
3. <exception>标记和cref 属性:文档化由成员代码引发的任何异常,exception表及必须包含cref属性,该属性的值指定正在文档编制的异常类型。cref得值必须用双引号括起来,该元素的文本描述引发这种异常的条件
/// <summary>
/// <exception cref=”System.Exception”>
/// Throws a FileIOException when…
/// </exception>
/// </summary>
public void Foo() {}
4. <c>:表明注释的某部分应该作为代码看待, <code>:表明注释中的多行文本作为代码看待, 和<example>:提供其他开发人员如何使用另一个人开发的类的示例,通常示例包含了一个代码样本,并且可以结合使用<example>和<code>标记
/// <summary>
/// <c>Hoo</c> is a method in the <c>Class1</c> class.
/// </summary>
public void Hoo() {}
/// <summary>
/// The Joo method.
/// <example>This example shows how to use Joo:
/// <code>
/// <newpara/>
/// public static void Main()
/// {
/// Console.WriteLine(Class1.Joo());
/// }
/// <newpara/>
/// </code>
/// </example>
/// </summary>
public static int Joo() { return 0; }
5. <include> 标记
语法:
<include file=’filename’ path=’tagpath[@name="id"]‘ />
/// <include file=’supporting.xml’ path=’MyDocs/MyMembers[@name="Class1"]/*’ />
class Class1{
public static void Main() {}
}
supporting.xml
<MyDocs>
<MyMembers name=”Class1″>
<summary>
The summary for this type.
</summary>
</MyMembers>
<MyMembers name=”Class2″>
<summary>
Another type description.
</summary>
</MyMembers>
</MyDocs>
6. <list>标记:描述文当中的列表项。可以描述圆点列表、已编号列表或者表格。<list>标记使用属性type描述列表的类型。
语法:
<list type=”bullet” │ “number” │ “table”>
<listheader>
<term>term</term>
<description>description</description>
</listheader>
<item>
<term>term</term>
<description>description</description>
</item>
</list>
/// <remarks>Here is an example of a bulleted list:
/// <list type=”bullet”>
/// <item>
/// <description>Item 1.</description>
/// </item>
/// <item>
/// <description>Item 2.</description>
/// </item>
/// </list>
/// </remarks>
static void Main(string[] args) {}
7、<remarks>:添加信息,提供了对方法或者变量一起用法的概述如上例。
扩充
由于产生的文档是XML文件,使得我们对它的处理非常方便。如可以定义一个xls来让它产生符合我们需要的文档,如HTML、WORD等等。对于HTML,C#的编译器有内置的支持。我们可以使用标准的HTML标记来扩充它。但由于XML是well-formed的,因此对于一些没有</…>符号的HTML元素则必须作为一个XML有效元素使用。如<br>,对应为<br/>。
2、展开的形式
展开的形式多用于一个属性为我们自定义类的类型,比如我们定义了一个类,该类中的一个属性是另一个我们定义的类。在这种情况下属性浏览器默认是没有办法来进行类型转换的,所以显示为不可编辑的内容。如果我们要以展开的形式编辑这个属性就需要我们向上面一样来重写属性转换器。
我们首先定义一个自己的类来作为以后的属性类型。具体代码如下:
public class ExpandProperty
{
private int _intList=0;
public int IntList
{
get { return this._intList;}
set { this._intList=value; }
}
private string _strList=”Null”;
public string StrList
{
get { return this._strList;}
set { this._strList= value;}
}
}
然后我们在自己的另一个类中声明一个这个类型的属性,在这里如果我们不加任何的性质限制,属性浏览器是不能转换改属性的。具体实现该属性的代码如下:
private ExpandProperty _dropList;
[CategoryAttribute("自定义的复杂类型设置(包括自定义类型转换器)"),
TypeConverterAttribute(typeof(PropertyGridApp.ExpandConverter)),
ReadOnlyAttribute(false)]
public ExpandProperty DropList
{
get { return this._dropList;}
set { this._dropList= value;}
}
为了让属性浏览器能够编辑该属性,也就是说能够把该属性转换成字符串,而且能够从字符串转换成该类的一个实例需要我们写如下的代码:
/// <summary>
/// 可以展开的类型转换器
/// ExpandProperty
/// </summary>
public class ExpandConverter:System.ComponentModel.ExpandableObjectConverter
{
public ExpandConverter()
{
}
/// <summary>
/// 覆盖此方法已确定属性是否可以转换
/// </summary>
public override bool CanConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Type destinationType)
{
if (destinationType==typeof(PropertyGridApp.ExpandProperty))
return true;
return base.CanConvertTo(context,destinationType);
}
/// <summary>
/// 覆盖此方法并确保destinationType参数是一个String,然后格式化所显示的内容
/// </summary>
public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType)
{
if (destinationType == typeof (System.String) && value is PropertyGridApp.ExpandProperty)
{
PropertyGridApp.ExpandProperty source=(PropertyGridApp.ExpandProperty)value;
return source.IntList+”,”+source.StrList;
}
return base.ConvertTo(context,culture,value,destinationType);
}
/// <summary>
/// 覆盖此方法已确定输入的字符串是可以被转化
/// </summary>
public override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
{
if (sourceType==typeof(string))
return true;
return base.CanConvertFrom(context,sourceType);
}
/// <summary>
/// 覆盖此方法根据 ConvertTo() 方法的转换格式来把所输入的字符串转换成类,并返回该类
/// </summary>
public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
string s=(string)value;
int comma=s.IndexOf(“,”);
if (comma!=-1)
{
try
{
string intList=s.Substring(0,comma);
string strList=s.Substring(comma+1,s.Length-comma-1);
PropertyGridApp.ExpandProperty Ep=new ExpandProperty();
Ep.IntList=int.Parse(intList);
Ep.StrList=strList;
return Ep;
}
catch
{
return base.ConvertFrom(context,culture,value);
}
}
}
return base.ConvertFrom(context,culture,value);
}
}
编译之后的画面如下:

二:UI属性编辑器(UITypeEditor)
这里的属性编辑器的意思是能够实现上面提到的弹出对话框和下拉UI的形式。废话不说下面我们一一介绍。
1、 弹出对话框的形式
在本例中我使用了string类型的属性来显示版本的信息,大家可以随便的写各类的属性,这里只需要指定改属性的编辑器就可以了。
首先我们要建立一个string类型的属性,代码如下:
private string _appVer=”1.0″;
[CategoryAttribute("自定义编辑器"),
DefaultValueAttribute("1.0"),
DescriptionAttribute("版本信息"),
ReadOnlyAttribute(true),
EditorAttribute(typeof(AppVerConverter),typeof(System.Drawing.Design.UITypeEditor))]
public string AppVer
{
get {return this._appVer;}
set {this._appVer=value;}
}
大家可能已经注意到了在这个属性之多出了一个性质EditorAttribute(typeof(AppVerConverter),typeof(System.Drawing.Design.UITypeEditor)),具体的意思大家可以参考MSDN我在这里就不用多说了,那么我们看看AppVerConverter这个类是怎么实现的就可以了。具体代码如下:
/// <summary>
/// 自定义UI的属性编辑器(弹出消息)
/// </summary>
public class AppVerConverter:System.Drawing.Design.UITypeEditor
{
/// <summary>
/// 覆盖此方法以返回编辑器的类型。
/// </summary>
public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
return System.Drawing.Design.UITypeEditorEditStyle.Modal;
}
/// <summary>
/// 覆盖此方法以显示版本信息
/// </summary>
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
{
System.Windows.Forms.MessageBox.Show(“版本:1.0\n作者:张翔“,”版本信息“);
return value;
}
}
这里需要说明的是我们的属性编辑器必须从System.Drawing.Design.UITypeEditor继承,要不然就不能显示UI了。UITypeEditorEditStyle方法的返回值决定了改属性编辑器的类型大家可以参考msdn我在这里就不多说了。编译之后就可以看到如下的画面了:

2、 下拉UI的类型
下拉UI类型主要是提供给用户一个简单的界面来选择所要确定的属性,这种方式提供给用户非常友好的界面。下面的例子我们首先定义里一个Point类型的属性,在默认的情况下这种类型的属性是会以展开的形式来让用户编辑的。在这里我们扩展了他的功能,不仅仅能通过直接输入的方式来改变值,而且还可以下拉出来一个控件,用户可以在这个控件上根据鼠标的位置来确定具体的值。下面具体的代码:
private System.Drawing.Point _dropUI;
[CategoryAttribute("自定义编辑器"),
DefaultValueAttribute("1"),
DescriptionAttribute("下拉可视控件"),
ReadOnlyAttribute(false),
EditorAttribute(typeof(DropEditor),typeof(System.Drawing.Design.UITypeEditor))]
public System.Drawing.Point DropUI
{
get { return this._dropUI;}
set { this._dropUI=value; }
}
public class DropEditor:System.Drawing.Design.UITypeEditor
{
public override System.Drawing.Design.UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
{
return System.Drawing.Design.UITypeEditorEditStyle.DropDown;
}
public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, System.IServiceProvider provider, object value)
{
System.Windows.Forms.Design.IWindowsFormsEditorService iws=(System.Windows.Forms.Design.IWindowsFormsEditorService)provider.GetService(typeof(System.Windows.Forms.Design.IWindowsFormsEditorService));
if (iws!=null)
{
PropertyGridApp.DropUIControl UIControl=new PropertyGridApp.DropUIControl((System.Drawing.Point)value,iws);
iws.DropDownControl(UIControl);
return UIControl.Value;
}
return value;
}
}
internal class DropUIControl:System.Windows.Forms.UserControl
{
public DropUIControl(System.Drawing.Point avalue,System.Windows.Forms.Design.IWindowsFormsEditorService iws)
{
this.Value=avalue;
this._tmpvalue=avalue;
this._iws=iws;
this.SetStyle(System.Windows.Forms.ControlStyles.DoubleBuffer|System.Windows.Forms.ControlStyles.UserPaint|System.Windows.Forms.ControlStyles.AllPaintingInWmPaint,true);
this.BackColor=System.Drawing.SystemColors.Control;
}
private System.Drawing.Point _value;
public System.Drawing.Point Value
{
get { return this._value;}
set { this._value=value; }
}
private System.Drawing.Point _tmpvalue;
private System.Windows.Forms.Design.IWindowsFormsEditorService _iws;
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
string str=”X:”+this._tmpvalue.X.ToString()+” ;Y:”+this._tmpvalue.Y.ToString();
System.Drawing.Graphics g=e.Graphics;
System.Drawing.SizeF sizef= g.MeasureString(str,this.Font);
g.DrawString(str,
this.Font,
new System.Drawing.SolidBrush(System.Drawing.Color.Black),
(int)((this.Width-(int)sizef.Width)/2),
this.Height-(int)sizef.Height);
g.PageUnit=System.Drawing.GraphicsUnit.Pixel;
g.FillEllipse(new System.Drawing.SolidBrush(System.Drawing.Color.Red),
this.Value.X-2,
this.Value.Y-2,
4,
4);
}
protected override void OnMouseMove(System.Windows.Forms.MouseEventArgs e)
{
base.OnMouseMove(e);
this._tmpvalue=new System.Drawing.Point(e.X,e.Y);
this.Invalidate();
}
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs e)
{
base.OnMouseUp(e);
this.Value=this._tmpvalue;
this.Invalidate();
if (e.Button==System.Windows.Forms.MouseButtons.Left)
this._iws.CloseDropDown();
}
}
以上的代码度非常的简单,相信大家一定能够看懂,如果有不明白的地方看看帮助,那里面解释的非常的清楚。
在编写属性编辑器中我们都需要覆盖其中的EditValue这个方法,大家是否注意到了其中的object Value这个参数?其实这个参数就是已经装箱的属性值,在我们自定义的处理完这个值的时候同样可以返回一个装箱的值来确定已经修改的属性。在上面的两个例子中我们只是简单的使用了这个值,大家理解这个内容之后就可以做出更加个性化的编辑器了。
属性(property)作为c#语言中一个重要的组成部分,尤其是在我们自己编写组件的时候显得更加重要。我相信大家一定对其有一定的了解。但是大家是否注意到了一个非常关键得细节问题呢?那就是在大家使用任何得组件的时候都需要通过属性浏览器给每一属性赋值,而且更加友好的是对于每种不同类型属性都会自己的形式。比如:数字类型、字符串类型是默认简单的输入的形式,而如Font、Color类型的属性则可以对话框或下拉列表框的形式。不知道大家是否知道这些是如何编写的?其实这些功能都是通过属性(Property)的(Attribute)来实现的,下面我就这个问题和大家一起学习,不过在阅读本文之前要求大家对属性(Property)有一定的了解,好下面我们言归正传。
实际上Property和Attribute翻译成中文都是属性的意思,但是在英文中却有着微小的差别。因为在中文中不好区别Property和Attribute,所以我暂时的把这两个单词翻译成属性(Property)和性质(Attribute),如果有什么不对的地方请大家指出。
在C#中不仅仅属性有自己的性质,类、方法、事件等都有自己的性质,由于本人知识限,所以只能给大家介绍一下属性的性质了请大家原谅。
现在大家知道了性质,但是在C#中究竟什么是性质呢?下面我用一个例子来告诉大家,请看下面的一个WebService的例子:
[WebMethod]
public string HelloWorld()
{
return “Hello World by zhx”;
}
这是一个WebService中一个对外发布方法的例子,其中[WebMethod]就是这个方法的Attribute。在WebService中如果方法不加上这个性质就不能够对外发布,我在第一次用C#写WebService时就没用使用这个性质导致我还以为是我程序的错误了呢。
下面给大家看一个属性的性质的例子:
private int _value;
[DefaultValue(1)]
[Description("文本框的值")]
public int Value
{
get
{
return this._value
}
set
{
this._value=value;
}
}
大家把这两个性质[DefaultValue(1)]、[Description("文本框的值")]用到自己的性质以后,会发现什么?大家可以自己试验一下。属性的性质主要对.Net环境中的属性编辑器起到UI的作用,所以大家在编写完成代码的时候先要编译一下,然后再在窗体中引用呢自己的组件选定这个属性才能起到作用。好,下面我就向大家一一的介绍我知道的性质。
先从简单的给大家介绍:
1、 CategoryAttribute 大家从这个名字就可以看出来他的作用了,他的作用是把所定义的属性按照一定的类型分类,就好像大家在系统中看到的“外观”等的分类一样。
2、 DescriptionAttribute 不知道大家是否还记得在系统中当选中一个属性之后,在属性浏览器中的下方就会出现该属性的文字描述。这个性质就是起到了这样的功能。
3、 DefaultValueAttribute 顾名思义这个性质当然是设置默认值的功能了,当用户制定了改默认值后,属性浏览器就会以加粗的字体显示。
4、 ReadOnlyAttribute 这个性质也不难看出他是设置属性的只读性,这里的只读性可不是属性真正的只读性,在这里只是指出在属性浏览器中是否可以改写的性质。
5、 BrowerAbleAttribute 这个性质功能是指出在属性浏览器中是否可以浏览该属性。有一些属性是不希望在设计期间或者用属性浏览器改写的,就可以制定改性质。
这几个性质不仅可以单独使用,而且可以一起使用,下面是使用这几个性质的一个例子:
private string _appVer=”1.0″;
[CategoryAttribute("自定义编辑器"),
DefaultValueAttribute("1.0"),
DescriptionAttribute("版本信息"),
ReadOnlyAttribute(true),
BrowerAbleAttribute(true)]
public string AppVer
{
get {return this._appVer;}
set {this._appVer=value;}
}
在编译、选定改属性之后可以看到如下的画面。其中以红色椭圆型标出的就是DescriptionAttribute性质所起到的作用,而其他性质得到的UI作用是在红色矩形框中所展现的内容。


不知道大家是否发现在我的属性AppVer和你的有一点不一样?大家仔细看看,对了就是在我的属性后面还多出了一个浏览按钮
,而且单击他会弹出一个对话框,显示版本信息,大家一定想知道这个功能是作用做出来的,大家先不要着急后面我在向大家介绍。
不知道大家是否注意到了,我们在使用Size、Font、Color等类型作为属性的时候属性浏览器会以怎样的形式来改变我们属性的值呢?下面的三个画面。



大家仔细的研究一下就可看出这三个属性可以分为基本的四个类型,Enum是下拉列表框的形式、Size是展开的形式、Font是弹出窗体的形式、Color是下拉UI的形式。但是对于性质的角度却分为两种类型,前两类Enum、Size需要的性质是属性转换器(TypeConverter),而后两种形式是需要编辑器(UITypeEditor)的。下面我就分别介绍这两种性质。
一:属性转换器(TypeConverter)
1、 下拉列表框的形式:
要使用下拉列表框的形式的属性我们首先要定义一个属性,在这个例子中我定义了一个字符串类型的属性 FileName。
private string _fileName;
public string FileName
{
get { return this._fileName;}
set { this._fileName=value; }
}
定义完属性之后,我们还要自己一个属性转换器。那么什么是属性转换器呢?其实在属性浏览器中只能够识别字符串类型,所以我们要通过属性转换器把我们的属性转换成字符串,还要在属性浏览器改变这个字符串之后在把这个字符串转换成我们自己的属性。大家听起来是不是有一些胡涂了?没关系下面我们做一个属性转换器大家就知道了。
因为在本例中用的属性是字符串类型的所以我们要从System.ComponentModel.StringConverter继承一个新的字符串形式的属性转换器。下面就是这段代码和代码中的注释,相信大家一定能够看懂的:
/// <summary>
/// 扩展字符串的转换器(实现下拉列表框的样式)
/// </summary>
public class FileNameConverter:System.ComponentModel.StringConverter
{
/// <summary>
/// 根据返回值确定是否支持下拉框的形式
/// </summary>
/// <returns>
/// true: 下来框的形式
/// false: 普通文本编辑的形式
/// </returns>
public override bool GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
/// <summary>
/// 下拉框中具体的内容
/// </summary>
public override System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(System.ComponentModel.ITypeDescriptorContext context)
{
return new StandardValuesCollection(new string[]{“File1.bat”,”File2.exe”,”File3.dll”});
}
/// <summary>
/// 根据返回值确定是否是不可编辑的文本框
/// </summary>
/// <returns>
/// true: 文本框不可以编辑
/// flase: 文本框可以编辑
/// </returns>
public override bool GetStandardValuesExclusive(System.ComponentModel.ITypeDescriptorContext context)
{
return true;
}
好了,属性转换器写完了,最后别忘了把这个属性转换器指定到我们刚才所写的属性上哦,代码如下:
[CategoryAttribute("自定义的复杂类型设置(包括自定义类型转换器)"),
TypeConverterAttribute(typeof(PropertyGridApp.FileNameConverter)),
ReadOnlyAttribute(false)]
public string FileName
{
get { return this._fileName;}
set { this._fileName=value; }
}
编译之后的程序画面如下:

Slashdot:Mono是一个雄心勃勃的计划,利用Microsoft自己用了数不尽的投资开发的.Net或者称为“通用语言运行时(CLR)”来让开发者转移到Linux和其他开放平台上。
如果Mono能够继续发展下去并且取得更多的开发者的支持,那就可以让本来只能在Windows上运行的.Net Platform程序顺利的移至到Linux平台上。虽然Microsoft也乐意看到自己的CLR有更多的实现,就如同Sun也不反对IBM或者SAP生产自己的JRE。不过和Sun不同的是,Microsoft绝对不会愿意看到本来使用Windows的人会转到他们的死对头Linux上。
这对Microsoft是一个两难,尽管他们一开始就已经准备好让.Net能够支持多平台。现在Mono不等Micorosoft的反应,已经得到了迅速的发展。项目领导人也清楚地知道可能存在的版权问题,不过他们认为Micorosft的已经成为ECMA标准的CLR允许“合理的和非歧视性的”使用,应该不会有什么问题。Mono同时实现了Windows API和GTK,不知道Microsoft会不会对此表示责难。
Mono已经有了一个据说很好的IDE-MonoDevelop。而且Internet上也已经出现了一些用Mono开发的应用程序,比如Muine音乐播放器和Blam RSS聚合器。看来同时喜欢C#和Linux的人还不少,虽然很多人出于面子问题不愿意承认。
Open Source的开发通常都是非常令人兴奋的不过最后往往就杳无音讯了,这次由Novell资助的庞大计划不知道是不是到最后真的能够和微软唱对台戏。各位有意思的人可以去下载一下试试看,尝试尝试在Linux上运行C#程序的感觉。