2010-08-24 64 views
7

我喜歡PropertyGrid,至少它背後的概念 - 使用反射和屬性來編輯對象而無需編寫太多的UI代碼。PropertyGrid替代

雖然我的興奮很快就消失了,但默認的PropertyGrid與WinForms一起運輸的情況非常糟糕。那麼編輯簡單的對象就可以了,但是就這麼簡單。

  • 它不顯示具有類型「對象」的動態屬性適當的UITypeEditors。
  • 只要對象包含集合,您可以使用所謂的CollectionEditor對其進行編輯。但是,它不會觸發PropertyValueChanged事件。所以,一旦你需要添加撤消功能,你就被搞砸了。
  • 而我仍然沒有找到一個優雅的方式來爲CollectionEditor添加驗證。
  • 如果您選擇了多個對象,實現撤銷也是有問題的,因爲在這種情況下,PropertyValueChanged事件參數ChangedItem爲null。

我很快就發現自己寫黑客來解決這些問題的結果並不理想。

你會怎麼做? 至少前三個問題是否有一個優雅的解決方案? 有沒有其他propertygrid?最好是免費&沒有PInvokes?

+0

至於集合的屬性已更改。如果有些東西改變了集合實例的參考,我會擔心。想想看。 – leppie 2010-08-25 05:17:18

回答

5

很多PropertyGrid的優雅來自它的簡單。最重要的是,它的設計與Visual Studio相得益彰,我期望看到它主要用於自定義UITypeEditor和擴展,而不是在應用程序代碼中。

假設您附加到PropertyGrid的物體是您自己設計的類?我發現,爲了充分利用屬性網格,你必須用屬性大量地裝飾你的類和成員。

您可以編寫自己的子類CollectionEditor(和其他類型的編輯器),並使用[Editor]屬性將它們附加類成員找到一些快樂 - 如果你能這個屬性附加到您的動態屬性,你可以強制使用的特定編輯器。

我認爲向CollectionEditor添加驗證的唯一方法是覆蓋CreateCollectionForm()方法,返回CollectionEditor.CollectionForm自己的自定義子類的實例。您有機會從這裏開始更改活動。

不幸的是,我所能做的只是點頭並同意關於實現撤消的斷言。您可能不得不通過克隆或序列化來「備份」受影響的對象,以實現撤消。

我已經看到內置屬性網格控件的替代品,但它們主要存在以提供不同的視覺樣式。

2

如果有人感興趣 - 這裏是一個PropertyValueChanged問題的解決方法,它通過調用System.Object的MemberwiseClone函數來模擬更改(如果CollectionEditor的PropertyValueChanged已被觸發)...

public class FixedCollectionEditor : CollectionEditor 
{   
    bool modified; 

    public FixedCollectionEditor(Type type) 
     : base(type) 
    { } 

    public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value) 
    {    
     value = base.EditValue(context, provider, value); 
     if (value != null && modified) 
     { 
      value = value.GetType() 
       .GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic) 
       .Invoke(value, new object[] { });     
     } 
     modified = false; 
     return value; 
    } 

    protected override CollectionForm CreateCollectionForm() 
    { 
     CollectionForm collectionForm = base.CreateCollectionForm(); 

     foreach (Control table in collectionForm.Controls) 
     { 
      if (!(table is TableLayoutPanel)) { continue; } 
      foreach (Control c1 in table.Controls) 
      { 
       if (c1 is PropertyGrid) 
       { 
        PropertyGrid propertyGrid = (PropertyGrid)c1; 
        propertyGrid.PropertyValueChanged += new PropertyValueChangedEventHandler(GotModifiedHandler); 
       } 
       if (c1 is TableLayoutPanel) 
       { 
        foreach (Control c2 in c1.Controls) 
        { 
         if (!(c2 is Button)) { continue; } 
         Button button = (Button)c2; 
         if (button.Name == "addButton" || button.Name == "removeButton") 
         { 
          button.Click += new EventHandler(GotModifiedHandler); 
          if (button.ContextMenuStrip != null) 
          { 
           button.ContextMenuStrip.ItemClicked += new ToolStripItemClickedEventHandler(GotModifiedHandler); 
          } 
         } 
        } 
       } 
      } 
     } 
     return collectionForm; 
    } 

    void GotModifiedHandler(object sender, EventArgs e) 
    { 
     modified = true; 
    } 
} 
1

Visualhint出售物業網格的替代品,可能有所幫助。因爲我從來沒有在一個真實的項目中使用過它,所以我不知道它有多好。