2010-01-12 13 views
5

Próbuję użyć System.Windows.Forms.PropertyGrid.Dlaczego atrybut Browsable sprawia, że ​​właściwość nie jest powiązana?

Aby utworzyć właściwość niewidoczną w tej tabeli, należy użyć zestawu BrowsableAttribute ustawionego na false. Jednak dodanie tego atrybutu powoduje, że właściwość nie jest wiążąca.

Przykład: Utwórz nowy projekt Windows Forms i upuść TextBox i PropertyGrid na Form1. Korzystanie poniższy kod, szerokość TextBox nie zostanie zobowiązany do Data.Width:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     Data data = new Data(); 
     data.Text = "qwe"; 
     data.Width = 500; 

     BindingSource bindingSource = new BindingSource(); 
     bindingSource.Add(data); 

     textBox1.DataBindings.Add("Text", bindingSource, "Text", true, 
      DataSourceUpdateMode.OnPropertyChanged); 
     textBox1.DataBindings.Add("Width", bindingSource, "Width", true, 
      DataSourceUpdateMode.OnPropertyChanged); 

     propertyGrid1.SelectedObject = data; 
    } 
} 

Kod dla klasy danych jest:

public class Data : IBindableComponent 
{ 
    public event EventHandler TextChanged; 
    private string _Text; 
    [Browsable(true)] 
    public string Text 
    { 
     get 
     { 
      return _Text; 
     } 
     set 
     { 
      _Text = value; 
      if (TextChanged != null) 
       TextChanged(this, EventArgs.Empty); 
     } 
    } 

    public event EventHandler WidthChanged; 
    private int _Width; 
    [Browsable(false)] 
    public int Width 
    { 
     get 
     { 
      return _Width; 
     } 
     set 
     { 
      _Width = value; 
      if (WidthChanged != null) 
       WidthChanged(this, EventArgs.Empty); 
     } 
    } 

    #region IBindableComponent Members 

    private BindingContext _BindingContext; 
    public BindingContext BindingContext 
    { 
     get 
     { 
      if (_BindingContext == null) 
       _BindingContext = new BindingContext(); 

      return _BindingContext; 
     } 
     set 
     { 
      _BindingContext = value; 
     } 
    } 

    private ControlBindingsCollection _DataBindings; 
    public ControlBindingsCollection DataBindings 
    { 
     get 
     { 
      if (_DataBindings == null) 
       _DataBindings = new ControlBindingsCollection(this); 

      return _DataBindings;  
     } 
    } 

    #endregion 

    #region IComponent Members 

    public event EventHandler Disposed; 

    public System.ComponentModel.ISite Site 
    { 
     get 
     { 
      return null; 
     } 
     set 
     { 

     } 
    } 

    #endregion 

    #region IDisposable Members 

    public void Dispose() 
    { 
     throw new NotImplementedException(); 
    } 

    #endregion 
} 

Jeśli zmienisz atrybut Browsable true na każdej nieruchomości w Data działa. Teraz wygląda na to, że BindingSource przeszukuje źródła danych według Browsable Attribute.

Odpowiedz

6

Updated odpowiedź oparta na przykład zmiana:

Zrobiłem trochę kopania w reflektor i odkrył, że „problem” jest rzeczywiście w ListBindingHelper, który jest używany przez CurrencyManager, który jest z kolei używany przez BindingSource (wszystkie są w przestrzeni nazw System.Windows.Forms).

Aby wykryć właściwości wiążące, CurrencyManager wywołuje ListBindingSource.GetListItemProperties. Pod maską, to wywołuje GetListItemPropertiesByInstance (kiedy przechodzisz w jednym obiekcie). Metoda ta ma następującą linię kodu na końcu:

return TypeDescriptor.GetProperties(target, BrowsableAttributeList); 

i wdrażania BrowsableAttributeList jest:

private static Attribute[] BrowsableAttributeList 
{ 
    get 
    { 
     if (browsableAttribute == null) 
     { 
      browsableAttribute = new Attribute[] { new BrowsableAttribute(true) }; 
     } 
     return browsableAttribute; 
    } 
} 

Widać, że to jest w rzeczywistości, filtrowanie właściwości przez BrowsableAttribute(true). Powinien raczej używać zamiast tego BindableAttribute, ale domyślam się, że projektanci zdali sobie sprawę, że wszyscy byli już uzależnieni od BrowsableAttribute i postanowili użyć tego.

Niestety, nie będziesz w stanie obejść tego problemu, jeśli używasz BrowsableAttribute. Twoje jedyne możliwości to albo zrobienie tego, co sugeruje Marc, i użycie niestandardowego TypeConverter, albo filtrowanie samej siatki właściwości za pomocą jednego z rozwiązań w tym pytaniu: Programatically Hide Field in PropertyGrid.

+0

Tak, masz rację. Wydaje się działać. Mam ten problem w dużym projekcie. Postaram się wkrótce napisać lepszy przykład. – bodziec

3

BrowsableAttribute jest używany przez wiele elementów modelu komponentu jako mechanizm, aby uniknąć jego uwzględnienia. Być może najlepszą opcją jest nie dodawanie [Browsable(false)].

Istnieje kilka innych sposobów filtrowania PropertyGrid, w tym (w rosnącej złożoności) TypeConverter, ICustomTypeDescriptor, TypeDescriptionProvider - ale najprostsze prawdopodobnie powiedzieć PropertyGrid atrybuty, które opisują rzeczy robisz Chcesz (.BrowsableAttributes) i zaznaczyć inne właściwości.

Zauważ, że inną opcją jest utworzenie niestandardowej karty - ale jest to moje doświadczenie w hit'n'miss.

Oto przykład użycia TypeConverter, który jest używany przez PropertyGrid, ale nie przez większość innych powiązań; działa poprzez niestandardowego typu konwerter który wyklucza konkretnej nieruchomości według nazwy, ale można też użyć coś jak Attribute.IsDefined zrobić maskowanie:

using System.Windows.Forms; 
using System; 
using System.Linq; 
using System.ComponentModel; 
static class Program 
{ 
    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Data data = new Data { Name = "the name", Value = "the value" }; 
     using (Form form = new Form 
     { 
      Controls = 
      { 
       new PropertyGrid { 
        Dock = DockStyle.Fill, 
        SelectedObject = data 
       }, 
       new TextBox { 
        Dock = DockStyle.Bottom, 
        DataBindings = { {"Text", data, "Value"}, } 
       }, 
       new TextBox { 
        Dock = DockStyle.Bottom, 
        DataBindings = { {"Text", data, "Name"}, } 
       } 
      } 
     }) 
     { 
      Application.Run(form); 
     }   
    } 
} 
[TypeConverter(typeof(DataConverter))] 
class Data 
{ 
    class DataConverter : ExpandableObjectConverter 
    { 
     public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) 
     { 
      var props = base.GetProperties(context, value, attributes); 
      return new PropertyDescriptorCollection(
       (from PropertyDescriptor prop in props 
       where prop.Name != "Value" 
       select prop).ToArray(), true); 
     } 
    } 
    public string Value { get; set; } 
    public string Name { get; set; } 
} 
Powiązane problemy