2010-01-12 21 views
5

Estoy tratando de usar System.Windows.Forms.PropertyGrid.¿Por qué el atributo Browsable hace que la propiedad no sea vinculable?

Para hacer una propiedad no visible en esta cuadrícula, se debe usar BrowsableAttribute establecido en false. Pero agregar este atributo hace que la propiedad no sea vinculable.

Ejemplo: Crear un nuevo proyecto de Windows Forms, y soltar un TextBox y PropertyGrid en Form1. Con el siguiente código, el ancho de la TextBox no quede obligado a 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; 
    } 
} 

El código para la clase de datos es:

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 
} 

Si cambia el atributo navegable true en cada propiedad en Datos funciona Ahora parece que BindingSource busca el origen de datos por el atributo de búsqueda.

Respuesta

6

respuesta actualizada basada en la actualización ejemplo:

que he hecho algo de investigación en el reflector y descubrieron que el "problema" es en realidad en ListBindingHelper, que es utilizado por CurrencyManager, que a su vez utilizado por el BindingSource (todos están en el espacio de nombre System.Windows.Forms).

Para descubrir las propiedades enlazables, el CurrencyManager invoca ListBindingSource.GetListItemProperties. Debajo del capó, esto llama al GetListItemPropertiesByInstance (cuando pasas en un solo objeto). Ese método tiene la siguiente línea de código al final:

return TypeDescriptor.GetProperties(target, BrowsableAttributeList); 

y la implementación de BrowsableAttributeList es:

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

Se puede ver que es, de hecho, el filtrado de propiedades por BrowsableAttribute(true). Probablemente debería estar usando BindableAttribute, pero creo que los diseñadores se dieron cuenta de que todo el mundo ya dependía de BrowsableAttribute y decidieron usar ese en su lugar.

Desafortunadamente, no podrá evitar este problema si utiliza BrowsableAttribute. Sus únicas opciones son hacer lo que sugiere Marc y usar un TypeConverter personalizado, o filtrar la cuadrícula de propiedad usando una de las soluciones en esta pregunta: Programatically Hide Field in PropertyGrid.

+0

Sí, tiene usted razón. Parece funcionar. Tengo este problema en un proyecto larg. Trataré de escribir un mejor ejemplo pronto. – bodziec

3

BrowsableAttribute es utilizado por mucho del modelo de componente como un mecanismo para evitar que se incluya. Quizás la mejor opción es no agregar [Browsable(false)].

Hay varias otras maneras de filtrar PropertyGrid, incluyendo (en el aumento de la complejidad) TypeConverter, ICustomTypeDescriptor, TypeDescriptionProvider - pero la más sencilla es probablemente para contar PropertyGrid los atributos que describen cosas que haces falta (.BrowsableAttributes), y marque la otras propiedades.

Tenga en cuenta que otra opción es crear una pestaña personalizada, pero eso es hit'n'miss en mi experiencia.

Aquí hay un ejemplo usando TypeConverter, que es utilizado por PropertyGrid, pero no por la mayoría de las otras vinculaciones; funciona por tener un tipo de convertidor a medida que excluye una propiedad específica por su nombre, pero también se podría usar algo como Attribute.IsDefined para hacer el enmascaramiento:

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