Почему Доступный для просмотра атрибут делает свойство не связываемым?

Я пытаюсь использовать System.Windows.Forms.PropertyGrid.

Для создания свойства не видимым в этой сетке, нужно использовать BrowsableAttribute набор к false. Но добавление этого атрибута делает свойство не связываемым.

Пример: Создайте новый проект Windows Forms и отбросьте a 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
}

При переключении Доступного для просмотра атрибута на истинный на каждом свойстве в Данных, это работает. Теперь это походит на источник данных поисков BindingSource Доступным для просмотра Атрибутом.

5
задан Kev 14 May 2012 в 13:33
поделиться

2 ответа

BrowsableAttribute используется многими компонентами как механизм, чтобы избежать его включения. Возможно, лучший вариант - не добавлять [Browsable(false)].

Существует несколько других способов фильтрации PropertyGrid, в том числе (все сложнее) TypeConverter, ICustomTypeDescriptor, TypeDescriptionProvider - но самое простое, наверное, сказать 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; }
}
3
ответ дан 14 December 2019 в 01:09
поделиться

Обновленный ответ на основе примера обновления:

Я покопался в 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 , либо отфильтровать саму сетку свойств, используя одно из решений в этом вопросе: Программно скрыть поле в PropertyGrid .

6
ответ дан 14 December 2019 в 01:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: