派尔新闻    企业资源管理    媒体看派尔
登录 注册


>>
派尔新闻

>>
行业动态

>>
典型用户

>>
产品介绍

>>
友情连接

>>
用户讨论

>>
常用计算

>>
玻璃知识

>>
公司证书

>>
关于我们

>>
交通指南

>>
加盟派尔



Glass Software
 
The biggest glass company in china
 
The Biggest Glass Com. In Nanjing
 
Zhejiang Zhongli Glass
 
The Biggest Glass Factory In ShangHai
 
italy intermac glass division
 
bottero glass division
 
The Biggest Glass Com. In Shaoxing
 
lisecasia glass division

 


.Net经典文摘

作者 帖子:   為 Microsoft Visual Studio .NET 設計工具建立可設計式元件(转贴)下
lq
為 Microsoft Visual Studio .NET 設計工具建立可設計式元件(转贴)下
时间: Thursday, March 15, 2007 5:59 PM (中)
以相同方式出入:透過程式碼保存元件
  不同於以往的設計工具,.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 包含每個屬性名稱中不保存的值。

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

反之,.Net Framework 在這種情況下,則使用實行 ICollection 物件的集合。物件可建立出集合並傳送給其它物件,同時參照項目可視基本物件的變更而保持最新狀態。若另一物件也針對集合進行變更,則亦將同時通知該物件。對於使用集合的 .Net Framework 設計工具,還需要支援含有 Get 和 Set 的 All 屬性,且其類型必須為集合可保留的物件陣列。例如:

public class IntCollection : ICollection {
private int[] values;

public IntCollection(int[] intValues) {
this.values = (int[])intValues.Clone();
}

public int[] All {
get {
return (int[])values.Clone();
}
set {
values = (int[])value.Clone();
}
}

public int Count {
get {
if (values == null) {
return 0;
}
return values.Length;
}
}


[Browsable(false)]
public object SyncRoot {
get {
return this;
}
}

[Browsable(false)]
public bool IsReadOnly {
get {
return false;
}
}

[Browsable(false)]
public bool IsSynchronized {
get {
return true;
}
}
}


.Net Framework 的保存性機制,可保存或不保存本集合。若該集合由較先進的類型組成,如上述之 BoolIntString 範例類型,則需要利用與類型相關聯的 TypeConverter,為集合中每個項目建立有效的 PersistInfo (特別是 VS .NET 設計工具的 CreationBundle)。

元件設計工具
  如之前所述,.Net Framework 中的內建設計工具,足以滿足元件的多數要求。不過,.Net Framework 還包括元件設計工具的完整擴充性架構。所有設計工具皆以 System.ComponentModel.Design.IDesigner 介面為基礎,列示如下:

public interface IDesigner {

// 與本設計工具相關的元件
IComponent Component {get;}

// 與元件相關的設計階段動作,
// 如 TabControl 的「Add Tab」
DesignerVerb[] Verbs {get;}

// 處理設計工具所使用的任何資源。
// 設計工具在本次呼叫後即無法使用。
void Dispose();

// 呼叫以要求設計工具執行「預設動作」。
// 通常為了回應執行階段在元件上「連按兩下」
// 動作而呼叫。
void DoDefaultAction();

// 以既定元件來初始設定設計工具。
void Initialize(IComponent component);
}


不難看出,IDesigner 是相當直接的。設計工具透過 DesignerAttribute 與元件產生關聯:

[Designer("MyNameSpace.Design.MyComponentDesigner, MyNameSpace.DLL")]
Public class MyComponent : Component {
}


倘若 DesignerAttribute 未出現在類別中,則必須待找出設計工具位置後,才能夠跨越類別階層。在前述範例中,預設的 ComponentDesigner 可能位於元件基礎類別中,同時可供使用。有些設計工具會顯示出 UI,有些則不顯示。在 ComponentDesigner 中,由於元件通常沒有 UI,因此可以看到代表物件的圖示。另一方面,Win 表單控制項則有設計工具可於設計階段顯示出實際控制項。

圖 3:設計階段的 Win 表單控制項

請注意:位於設計工具下的圖示是未顯示 UI 的控制項;而顯示 UI 的 Win 表單控制項,則於執行階段顯示在表單設計工具中。然而不論顯示與否,這些控制項全數皆以 IDesigner 為基礎建立而成。控制項的設計工具通常會攔截設計中的控制項 WindowProc (來自System.WinForms.Design.ControlDesigner 的設計工具可以簡單地覆寫 WndProc 方法來完成),以執行諸如點擊測試等複雜的工作。然而,對於大部份元件而言,內建的預設設計工具應該已經足夠使用。

使用設計工具服務與基礎架構
  在 VS .NET 中的 .Net Framework 設計工具,顯露出多樣化服務和基礎架構元件,可簡化複雜的作業或允許設計工具了解有關其它部份的狀態。這些服務永遠使用 GetServiceObject 方法透過 IServiceObjectProvider 進行存取。以下是部分特殊設計工具服務的清單:

類型

 
描述

IDesignerHost
與任何最上層設計工具相關的主要類別。可提供方法以增加服務、建立與放置元件、移除元件並進行批次作業。

IComponentChangeService
新增、移除、重新命名或修改元件時提供通知。

ISelectionService
設定或取得目前設計工具中選取的項目。

IToolboxService
允許在工具箱內查驗和修改項目及選項狀態等等。

IUndoService
提供配備以建立動作的復原/重做單位,並管理復原/重做堆疊。

IHelpService
允許設定說明主題或者叫用說明項目。

IMenuCommandService
允許處理設計工具功能表指令和動作。

IReferenceService
在設計工具中將參照內容對應到物件。例如,名稱 button1 對應到元件 button1 。



IDesignerHost 是 VS .NET 中所有設計工具的基礎。IDesignerHost 亦為 IServiceObjectProvider,可利用動態方式新增和移除服務。它同時也提供建立元件的方法,以確保是否置於適當的位置。以下是使用 IDesignerHost 建立元件的範例:

Public class MyDesigner : IDesigner {

// ?.

Private void OnSurfaceDoubleClick(object s, EventArgs e) {
IDesignerHost host =
(IDesignerHost)this.Component.Site.GetServiceObject(typeof(IDesignerHost));
If (host != null) {
Object newComponent = host.CreateComponent(typeof(MyComponent));
DoSomethingInterestingWithComponent(newComponent);
}
}

// ?}


元件授權
  在擴充性的 .Net Framework 模型中,授權架構亦可同時擴充。為了方便使用,架構定義了一項內建的標準授權方法,以控制元件是否於設計使用階段獲得授權,不過研發人員可自由替換本機制。

// 新增 LicenseProviderAttribute 到控制項。
[LicenseProvider(typeof(LicFileLicenseProvider))]
public class MyControl : RichControl {
// 建立新的「空」授權。
private License license = null;
public MyControl () {
// 使控制項的建構函式生效。
license = LicenseManager.Validate(typeof(MyControl), this);
// 是否執行其他範例工作? }
public override void Dispose() {
if (license != null) {
license.Dispose();
license = null;
}
}
protected override void Finalize() {
Dispose();
base.Finalize();
}
}


此範例可以使用內建授權支援來啟動授權工作。LicFileLicenseProvider 只要在類別的 Assembly 目錄中,尋找名為 <classname>.lic 的檔案,其中 classname 必須是完整的類型名稱。例如,對於 String 類型而言,名稱則為 System.String.lic。本檔案可包含字串「System.String 是已授權的元件」。若發現本檔案,LicenseManager.Validate 會傳回授權物件,並隨著類別實例來進行處置。

實行您個人的授權機制也一樣輕鬆簡單。只要建立取自 LicenseProvider 的個人類別,並實行個人的 GetLicense 方法即可。您可以登錄為基礎實行授權機制,其中已授權的設計階段元件在登錄檔中有一個項目:

public class RegistryLicenseProvider: LicenseProvider {
public override License GetLicense(
LicenseContext context,
Type type,
object instance,
bool allowExceptions) {

RegistryKey licenseKey = Registry.LocalMachine.
OpenSubKey("Software\\MyCompany\\ComponentLicenses");

if (context.UsageMode == LicenseUsageMode.Designtime) {
if (licenseKey != null && licenseKey.GetValue(type.FullName) != null) {
return new RegLicense(this, type);
}
if (allowExceptions) {
throw new LicenseException(type, instance,
"Couldn''t get design-time license for ''"" +
type.FullName + "''");
}
return null;
}
else {
return new RuntimeRegLicense(this, type);
}
}

private class RuntimeRegLicense : License {
public string LicenseKey {
get {
return type.FullName;
}
}
public override void Dispose() {
}


}

private class RegLicense : License {
private RegistryLicenseProvider owner;
private Type type;

public RegLicense(RegistryLicenseProvider owner, Type type) {
this.owner = owner;
this.type = type;
}

public string LicenseKey {
get {
return type.FullName;
}
}
public override void Dispose() {
}
}

[LicenseProvider(typeof(RegistryLicenseProvider))]
public class MyControl : Control {
}


使用本授權的元件在下列登錄檔中會有一個登錄項目:

HKEY_LOCAL_MACHINE\Software\MyCompany\ComponentLicenses
<Type full name>="true"


結論
  在管理程式碼中撰寫控制項,可為傳統的 C++/COM 方法帶來更多的優勢。Microsoft 從最基本的通用語言執行階段開始策劃,遍及至 C# 甚至重組的 Visual Basic 語言,以提供研發人員效率最高的通用方法,將建構軟體時的阻礙降到最低。Microsoft .Net Framework 是第一個以這些技術和原理為基礎,所研發成功的大型程式碼庫範例,而支援的整合式設計工具,則是本方法成功的關鍵。




新文章
  • 经济危机,对派尔玻璃软件而言是件好事
    07、08混乱的玻璃加工管理软件市场,很多企业都因为形势好,上管理软件比较盲目,没有认真去调研。09年经济危机,势必大家对选型会更加认真。而派尔的先免费试用,正合了市场需求,大家可以先在企业运行好了再投资购买,真正地零风险。

  • 派尔推出免费玻璃优化软件
    派尔推出自己的优化软件,和派尔玻璃加工管理软件无缝集成,一键式优化。在订单输入尺寸后,点“套料”按钮,立马进行优化。使用方便,优化率高!欢迎使用,下载地址:http://2009.glassoo.com

  • 浙江中力节能玻璃制造有限公司成功实施派尔玻璃软件
    浙江中力节能玻璃制造有限公司成功实施派尔玻璃软件

  •  

    New Posts

  • 房子为谁而盖
    作者: lq on Thursday, July 10, 2008 (中)

  • 马云在《赢在中国》对创业者的经典点评
    作者: lq on Tuesday, March 11, 2008 (中)

  • 毛主席论营销(转)
    作者: lq on Monday, February 18, 2008 (中)



  • 派尔新闻 | 行业动态 | 典型用户 | 产品介绍 | 友情连接 | 用户讨论 | 常用计算 | 玻璃知识 | 公司证书 | 关于我们 | 交通指南 | 加盟派尔
    CopyRight®派尔2004-2008 总机:086+571-87858522 售前:87858586 87858579 售后:85354225 85354245

    浙ICP备06025955号