为什么Browsable属性使属性不可绑定?

bod*_*iec 5 .net c# data-binding bindingsource winforms

我正在尝试使用System.Windows.Forms.PropertyGrid.

要使该属性在此网格中不可见,应使用BrowsableAttributeset to false.但添加此属性会使属性无法绑定.

例如:创建一个新的Windows窗体项目,拖放TextBoxPropertyGridForm1.使用下面的代码,宽度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;
    }
}
Run Code Online (Sandbox Code Playgroud)

数据类的代码是:

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
}
Run Code Online (Sandbox Code Playgroud)

如果您在Data中的每个属性上将Browsable属性切换为true,则它可以正常工作.现在看来BindingSource通过Browsable Attribute搜索数据源.

Aar*_*ght 6

根据更新示例更新了答案:

我已经在Reflector中进行了一些挖掘,并发现"问题"实际上是在ListBindingHelper使用的CurrencyManager,而问题又由BindingSource(这些都在System.Windows.Forms命名空间中)使用.

要发现可绑定属性,请CurrencyManager调用ListBindingSource.GetListItemProperties.在引擎盖下,这会调出GetListItemPropertiesByInstance(当您传入单个对象时).该方法最后有以下代码行:

return TypeDescriptor.GetProperties(target, BrowsableAttributeList);
Run Code Online (Sandbox Code Playgroud)

而实施BrowsableAttributeList是:

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

实际上,您可以看到它是通过过滤属性BrowsableAttribute(true).它可能应该使用BindableAttribute,但我的猜测是设计师意识到每个人都已经依赖BrowsableAttribute并决定使用那个.

所以很遗憾,如果你使用的话,你将无法解决这个问题BrowsableAttribute.您唯一的选择是要么做Marc建议并使用自定义TypeConverter,要么使用此问题中的一个解决方案过滤属性网格:在PropertyGrid中以编程方式隐藏字段.