2010-08-24 18 views
7

Uwielbiam PropertyGrid, cóż, przynajmniej koncepcja za nim - użyj refleksji i atrybutów do edycji swoich obiektów bez pisania zbyt wiele kodu UI.Alternatywne właściwości PropertyGrid

Moje podekscytowanie dość szybko wyszło, domyślna usługa PropertyGrid jest dostarczana z programem WinForms. Cóż, to jest w porządku do edycji prostych obiektów i takich, ale to jest tak daleko, jak to możliwe.

  • Nie wyświetla odpowiednich wskaźników UITypeEditors dla właściwości dynamicznych, które mają typ "Object".
  • Gdy tylko twoje obiekty zawierają kolekcje, możesz je edytować za pomocą tak zwanego CollectionEditor. Jednak nie uruchomi zdarzenia PropertyValueChanged. Więc gdy chcesz dodać funkcję cofania, jesteś spieprzony.
  • Nadal nie znalazłem eleganckiego sposobu dodawania sprawdzania poprawności dla CollectionEditor.
  • Problematyczne jest również zaimplementowanie cofnięcia, jeśli wybrano wiele obiektów, ponieważ w tym przypadku zmienna zdarzenia ValueVenda została null.

Wkrótce zacząłem pisać hacki, aby rozwiązać te problemy z mniej niż przyjemnymi wynikami.

Co byś zrobił? Czy istnieje eleganckie rozwiązanie co najmniej pierwszych trzech problemów? Czy istnieje alternatywna usługa? Najlepiej za darmo & bez PInvokes?

+0

Jeśli chodzi o propertychowaną kolekcję. Byłbym zmartwiony, gdyby coś zmieniło referencję instancji kolekcji. Pomyśl o tym. – leppie

Odpowiedz

5

Wiele z elegancji PropertyGrid pochodzi z jej prostoty. Przede wszystkim został zaprojektowany, aby grać ładnie z Visual Studio i spodziewałbym się, że będzie on używany głównie w niestandardowych UITypeEditor s i rozszerzeniach, a nie w kodzie aplikacji.

Prawdopodobnie przedmioty, które przyczepiasz do PropertyGrid, są klasami własnego projektu? Odkryłem, że aby dobrze wykorzystać własność siatki, musisz mocno udekorować swoje klasy i członków atrybutami.

Możesz mieć trochę radości z pisania własnych podklas CollectionEditor (i innych typów edytorów) i dołączania ich do członków klasy przy użyciu atrybutu [Editor] - jeśli możesz dołączyć ten atrybut do swoich właściwości dynamicznych, możesz wymusić użycie konkretnego edytora.

Jedynym sposobem mogę myśleć o dodanie walidacji do CollectionEditor ma zastąpić metodę CreateCollectionForm(), wracając instancję własnej, niestandardowej podklasy CollectionEditor.CollectionForm. Jest szansa, że ​​będziesz mógł wywołać wydarzenia związane z przemianą stąd.

Niestety, wszystko, co mogę zrobić, to kiwać głową i zgadzam się z twierdzeniem o wprowadzeniu cofnięcia. Być może będziesz musiał użyć kopii zapasowej zainfekowanych obiektów poprzez klonowanie lub serializację w celu wprowadzenia cofnięcia.

Widziałem alternatywę dla wbudowanej kontroli siatki własności, ale istnieją one głównie w celu oferowania różnych stylów wizualnych.

2

Jeśli ktoś jest zainteresowany - oto obejście problemu PropertyValueChanged, który symuluje zmianę przez wywołanie funkcji MemberwiseClone obiektu System.Object, jeśli właściwość PropertyValueChanged CollectionEditor została uruchomiona ...

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 sprzedaje zamiennik siatki nieruchomości, która może pomóc. Ponieważ nigdy nie używałem go w prawdziwym projekcie, nie wiem, jak dobrze to działa.

Powiązane problemy