2010-01-12 5 views
5

Ich versuche System.Windows.Forms.PropertyGrid zu verwenden.Warum Browsable-Attribut macht Eigenschaft nicht bindbar?

Um eine Eigenschaft in diesem Gitter nicht sichtbar zu machen, sollte BrowsableAttribute auf false eingestellt werden. Das Hinzufügen dieses Attributs macht die Eigenschaft jedoch nicht bindbar.

Beispiel: Erstellen eines neuen Windows Forms-Projekt und ein TextBox und PropertyGrid auf Form1 fallen. Verwenden Sie den Code unten, die Breite des TextBox erhält nicht zu Data.Width gebunden:

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; 
    } 
} 

Der Code für die Datenklasse ist:

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 
} 

Wenn Sie schalten Sie das Browsable Attribut auf true auf jede Eigenschaft in Daten funktioniert es. Nun scheint es, als ob BindingSource die Datenquelle nach dem Browsable-Attribut durchsucht.

Antwort

6

aktualisiert Antwort auf Update Beispiel basiert:

Ich habe einige graben in Reflector getan und festgestellt, dass das „Problem“ in ListBindingHelper tatsächlich ist, die von CurrencyManager verwendet wird, die wiederum durch die verwendet wird, BindingSource (diese befinden sich alle im Namespace System.Windows.Forms).

Um die bindbaren Eigenschaften zu ermitteln, ruft CurrencyManagerListBindingSource.GetListItemProperties auf. Unter der Haube ruft dies nach GetListItemPropertiesByInstance (wenn Sie ein einzelnes Objekt übergeben). Diese Methode hat die folgende Codezeile am Ende:

return TypeDescriptor.GetProperties(target, BrowsableAttributeList); 

und die Umsetzung von BrowsableAttributeList ist:

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

Sie können sehen, dass es in der Tat, filternden Eigenschaften von BrowsableAttribute(true). Es sollte wahrscheinlich BindableAttribute stattdessen verwenden, aber meine Vermutung ist, dass die Designer realisierten, dass jeder bereits auf BrowsableAttribute angewiesen war und entschieden, diesen stattdessen zu verwenden.

Leider können Sie dieses Problem nicht umgehen, wenn Sie BrowsableAttribute verwenden. Ihre einzigen Optionen sind, entweder das zu tun, was Marc vorschlägt, und eine benutzerdefinierte TypeConverter zu verwenden, oder das Eigenschaftenraster selbst zu filtern, indem Sie eine der Lösungen in dieser Frage verwenden: Programatically Hide Field in PropertyGrid.

+0

Ja, Sie haben Recht. Es scheint zu funktionieren. Ich habe dieses Problem in einem großen Projekt. Ich werde versuchen, bald ein besseres Beispiel zu schreiben. – bodziec

3

BrowsableAttribute wird von vielen der Komponenten-Modell als ein Mechanismus verwendet, um zu vermeiden, dass es enthalten ist. Vielleicht ist die beste Option, [Browsable(false)] nicht hinzuzufügen.

Es gibt mehrere andere Möglichkeiten der PropertyGrid Filterung, einschließlich (in zunehmender Komplexität) TypeConverter, ICustomTypeDescriptor, TypeDescriptionProvider - aber die einfachste ist wahrscheinlich PropertyGrid die Attribute zu sagen, dass die Dinge beschreiben Sie wollen tun (.BrowsableAttributes), und markieren Sie die andere Eigenschaften.

Beachten Sie, dass eine andere Option ist, eine benutzerdefinierte Registerkarte zu erstellen - aber das ist Hit'n'miss in meiner Erfahrung.

Hier ist ein Beispiel mit TypeConverter, das von PropertyGrid verwendet wird, aber nicht von den meisten anderen Bindungen; es funktioniert durch einen benutzerdefinierten Typ-Wandler, der eine bestimmte Eigenschaft mit Namen ausschließt, aber man könnte auch so etwas wie Attribute.IsDefined verwenden, um die Maskierung zu tun:

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; } 
}