I'm trying to use System.Windows.Forms.PropertyGrid
.
To make a property not visible in this grid one should use BrowsableAttribute
set to false
.
But adding this attribute makes the property not bindable.
Example: Create a new Windows Forms project, and drop a TextBox
and PropertyGrid
onto Form1
. Using the code below, the width of the TextBox
does not get bound to 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;
}
}
The code for the data class is:
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
}
If you switch the Browsable attribute to true on every property in Data it works. Now it seems like BindingSource searches datasource by Browsable Attribute.
BrowsableAttribute
is used by a lot of the component-model way as a mechanism to avoid it being included. Perhaps the best option is to not add[Browsable(false)]
.There are several other ways of filtering
PropertyGrid
, including (in increasing complexity)TypeConverter
,ICustomTypeDescriptor
,TypeDescriptionProvider
- but the simplest is probably to tellPropertyGrid
the attributes that describe things you do want (.BrowsableAttributes
), and mark the other properties.Note that another option is to create a custom tab - but that is hit'n'miss in my experience.
Here's an example using
TypeConverter
, which is used byPropertyGrid
, but not by most other bindings; it works by having a custom type-converter which excludes a specific property by name, but you could also use something likeAttribute.IsDefined
to do the masking:Updated answer based on update example:
I've done some digging in Reflector and discovered that the "problem" is actually in
ListBindingHelper
, which is used byCurrencyManager
, which is in turn used by theBindingSource
(these are all in theSystem.Windows.Forms
namespace).To discover the bindable properties, the
CurrencyManager
invokesListBindingSource.GetListItemProperties
. Under the hood, this calls out toGetListItemPropertiesByInstance
(when you pass in a single object). That method has the following line of code at the end:And the implementation of
BrowsableAttributeList
is:You can see that it is, in fact, filtering properties by
BrowsableAttribute(true)
. It should probably be usingBindableAttribute
instead, but my guess is that the designers realized that everybody was already depending onBrowsableAttribute
and decided to use that one instead.So unfortunately you won't be able to get around this issue if you use
BrowsableAttribute
. Your only options are to either do what Marc suggests and use a customTypeConverter
, or filter the property grid itself using one of the solutions in this question: Programatically Hide Field in PropertyGrid.