我正在尝试使用System.Windows.Forms.PropertyGrid
。
要使此网格中的属性不可见,应将BrowsableAttribute
设置为false
。
但添加此属性会使属性无法绑定。
示例:创建一个新的Windows窗体项目,并将TextBox
和PropertyGrid
放到Form1
上。使用下面的代码,TextBox
的宽度不会绑定到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;
}
}
数据类的代码是:
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
}
如果您在Data中的每个属性上将Browsable属性切换为true,则它可以正常工作。 现在看来BindingSource通过Browsable Attribute搜索数据源。
答案 0 :(得分:6)
根据更新示例更新了答案:
我在Reflector中进行了一些挖掘,发现“问题”实际上在ListBindingHelper
,CurrencyManager
使用了BindingSource
,而System.Windows.Forms
又使用了CurrencyManager
这些都在ListBindingSource.GetListItemProperties
命名空间中。
要发现可绑定属性,GetListItemPropertiesByInstance
会调用return TypeDescriptor.GetProperties(target, BrowsableAttributeList);
。在引擎盖下,这会调用BrowsableAttributeList
(当您传入单个对象时)。该方法最后有以下代码行:
private static Attribute[] BrowsableAttributeList
{
get
{
if (browsableAttribute == null)
{
browsableAttribute = new Attribute[] { new BrowsableAttribute(true) };
}
return browsableAttribute;
}
}
BrowsableAttribute(true)
的实施是:
BindableAttribute
您可以看到它实际上是按BrowsableAttribute
过滤属性。它可能应该使用BrowsableAttribute
,但我的猜测是设计师意识到每个人都已经依赖TypeConverter
而决定使用那个。{/ p>
很遗憾,如果使用{{1}},您将无法解决此问题。您唯一的选择是执行Marc建议并使用自定义{{1}},或使用此问题中的一种解决方案过滤属性网格:Programatically Hide Field in PropertyGrid。
答案 1 :(得分:3)
BrowsableAttribute
作为避免包含它的机制。也许最好的选择是不添加[Browsable(false)]
。
还有其他几种方法可以过滤PropertyGrid
,包括(越来越复杂)TypeConverter
,ICustomTypeDescriptor
,TypeDescriptionProvider
- 但最简单的方法可能就是{{1}描述做想要的内容(PropertyGrid
)的属性,并标记其他属性。
请注意,另一个选项是创建一个自定义标签 - 但根据我的经验,该标签很少见。
以下是使用.BrowsableAttributes
的示例,TypeConverter
使用了PropertyGrid
,而不是大多数其他绑定使用的示例。它的工作原理是使用自定义类型转换器,它按名称排除特定属性,但您也可以使用Attribute.IsDefined
之类的东西进行屏蔽:
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; }
}