日期:2008-04-20  浏览次数:20391 次

以相同方式出入:透過程式碼保存元件
  不同於以往的設計工具,.Net Framework 元件的 Win Forms 與其它 VS .NET 設計工具,僅依賴表單狀態的程式碼保存性。沒有神奇的格式,也沒有隱藏資料,只是運作平穩的普通程式碼。當然,像點陣圖和本土化字串等,可以視為二進元資料與程式碼一起封裝,但元件狀態和元件所含內容,則必須透過程式碼來保存。在您設計工具的同時,也會產生程式碼。倘若您針對該程式碼進行處理,則會重新剖析,並且將變更內容反應在設計工具中。

.Net Framework 的設計工具可提供所有配備以利用此功能。所有設計工具對於任何類型最希望得知的內容包括:

有哪些關於物件狀態的資訊有助於保存性?

如何將該類資訊以現行物件傳回?

在先前的章節中,已經簡單討論過這個問題。再次聲明,TypeConverter 是處理的核心。產生程式碼和剖析程式碼設計工具,皆與名為 CreationBundle 的 PersistInfo 特定類型有關。例如:

[TypeConverter(typeof(IntBoolString.IntBoolStringConverter))]
public class IntBoolString {
private int intVal;
private string stringVal;
private bool boolVal;

public IntBoolString(string s, int I, bool b) {
This.intVal = I;
This.stringVal =s ;
This.boolVal = b;
}
public bool Bool{
get {return boolVal;}
set {boolVal = value;}
}

public int Int {
get {return intVal;}
set {intVal = value;}
}

public string String {
get {return stringVal;}
set {stringVal = value;}
}

public override string ToString() {
return intVal + "," + boolVal + "," + stringVal;
}

public class IntBoolStringConverter : TypeConverter {

public override bool CanConvertFrom(
ITypeDescriptorContext context,
Type sourceType) {
return (sourcetType == typeof(string));
}

public virtual object ConvertFrom(
ITypeDescriptorContext context,
object value,
object[] arguments) {

if (value is string) {
string stringValue = (string)value;
int intValue;
bool boolValue;

int commaIndex =
stringValue.IndexOf(',');

if (commaIndex != -1) {
intValue = Int32.
Parse(stringValue.
Substring(0, commaIndex));
commaIndex = stringValue.
IndexOf(',',
commaIndex + 1);
if (commaIndex != -1) {
int nextComma = stringValue.IndexOf(',', commaIndex + 1);
if (nextComma != -1) {
boolValue = Boolean.Parse(stringValue.Substring(commaIndex+1,
nextComma - commaIndex));
stringValue = stringValue.Substring(nextComma+1);
return new IntBoolString(intVal, boolVal, stringValue);
}

}
}
throw new FormatException("Can't convert '" + stringValue + "' to IntBoolString Object");
}
}



public override PersistInfo GetPersistInfo(ITypeDescriptorContext context, object value) {
if (value is IntBoolString) {
IntBoolString ibs = (IntBoolString)value;

return new CreationBundle(typeof(IntBoolString), null,
new CreationArgument[] {
new CreationArgument(ibs.Int, typeof(Int32)),
new CreationArgument(ibs.Bool, typeof(bool)),
new CreationArgument(ibs.String, typeof(string))});
}

return base.GetPersistInfo(context, value);
}
}

public override object CreateInstance(ITypeDescriptorContext
context, IDictionary propertyValues) {
return new IntBoolString((int)propertyValues["Int"],
(bool)propertyValues["Bool"],
(string)propertyValue["String"]);
}

public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) {
return true;
}

}


使用 CreationBundle 物件的好處,在於這些物件若擁有符合傳入 CreationArgument 中各種類型的建構函式,就能夠得知用來儲存資訊的物件建立方式。在呼叫 TypeConverter::CreateInstance,並以此方式嘗試建立和初始設定物件時,TypeConverter 的預設實作會呼叫 CreationBundle::Invoke。倘若無可用的建構函式,則 CreateInstance 呼叫會採用 IDictionary,以允許物件製作更多自訂項目。傳入的 IDictionary 包含每個屬性名稱中不保存的值。

元件的屬性值通常由多個物件所組成,其它架構通常就是為此目的而使用屬性陣列。然而,陣列卻有些缺點,例如,陣列必須在傳出時先行複製,於傳回時再次複製,結果當然大幅影響效能;在新增、修改或刪除值的時候,陣列也無法提供智慧型通知。事實上,如果屬性傳回陣列,是否新增或刪除項目就相當耗費工夫。陣列也是快照值,若基本物件不變更,就無法進行更新。

反之,.Ne