8

Tengo una aplicación Winform que utiliza el color para resaltar ciertas cosas. Me gustaría permitir que los usuarios cambien 'sus' colores. Como ejercicio, pensé en crear una instancia de una clase, con propiedades para los colores, y asignarla a una cuadrícula de propiedades (para obtener un buen editor).¿PropertyGrid no nota las propiedades cambiadas en el código?

Esto parece funcionar bien, pero luego pensé que me gustaría dejar que los usuarios reiniciaran los colores (después de haber manipulado y configurado 20 tonos de beige). Entonces, agregué un botón "restablecer" a mi formulario, que establece las propiedades de color de mi objeto a los valores predeterminados.

Sin embargo, parece que si bien restablece las propiedades de mis objetos, la cuadrícula de propiedad no cambia. Si, después del reinicio, hago una cuadrícula de propiedad "Refresh", tiene el color de reinicio.

Supongo que la cuadrícula de propiedad no sabe que el objeto subyacente se ha cambiado?

¿Falta algo en este escenario, o debería simplemente aceptarlo y llamar al método Refresh cuando restablezco mi objeto?

Gracias

(pregunta muy similar here)

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
    InitializeComponent(); 

    this.propertyGrid1.SelectedObject = new Colours(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
    Colours colours = this.propertyGrid1.SelectedObject as Colours; 
    colours.Reset(); 
    } 
} 

public partial class Colours : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public Color ColourP1 { get; set; } 

    public void Reset() 
    { 
    this.ColourP1 = Color.Red; 
    var handler = this.PropertyChanged; 
    if (handler != null) handler(this, new PropertyChangedEventArgs("ColourP1")); 
    } 
} 

A raíz de mi comentario de "no se suscribe a la INotifyPropertyChanged.PropertyChanged", ¿cuál es el inconveniente de subsclassing el control PropertyGrid para que lo haga?

public partial class MyPropertyGrid : System.Windows.Forms.PropertyGrid 
{ 
    private INotifyPropertyChanged _selectedObject; 

    protected override void OnSelectedObjectsChanged(EventArgs e) 
    { 
    base.OnSelectedObjectsChanged(e); 

    if (_selectedObject != null) _selectedObject.PropertyChanged -= selectedObject_PropertyChanged; 
    _selectedObject = this.SelectedObject as INotifyPropertyChanged; 
    if (_selectedObject != null) _selectedObject.PropertyChanged += selectedObject_PropertyChanged; 
    } 

    private void selectedObject_PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
    this.Refresh(); 
    } 
} 

Respuesta

9

Para responder a su pregunta sobre por qué el PropertyGrid no cambia, la documentación de MSDN para el PropertyGrid diga esto:

La información que se muestra en la cuadrícula es una instantánea de las propiedades en el momento en que se asigna el objeto. Si el valor de propiedad del objeto especificado por SelectedObject se cambia en código en tiempo de ejecución, el nuevo valor no se muestra hasta que se realiza una acción en la cuadrícula que hace que la cuadrícula se actualice.

Parece que el PropertyGrid no es un control auto actualizable. Creo que la clave para esto es que PropertyGrid usa el método SelectedObject en lugar de un método DataSource, y lo último implicaría que probablemente escuche INotifyPropertyChanged.

Le queda lo que LarsTech ha sugerido y actualiza manualmente la cuadrícula.

+0

Sí, eso lo resume todo. – LarsTech

6

Solo trata refrescante que:

private void button1_Click(object sender, EventArgs e) 
{ 
    Colours colours = this.propertyGrid1.SelectedObject as Colours; 
    colours.Reset(); 
    this.propertyGrid1.Refresh(); 
} 

Suponiendo que tendrá más propiedades, puede utilizar su evento PropertyChanged. Me gustaría modificar su clase Color como esto:

public class Colours : INotifyPropertyChanged { 
    public event PropertyChangedEventHandler PropertyChanged; 

    private Color _ColourP1; 

    public void Reset() { 
    this.ColourP1 = Color.Red; 
    } 

    private void OnChanged(string propName) { 
    if (PropertyChanged != null) 
     PropertyChanged(this, new PropertyChangedEventArgs(propName)); 
    } 

    public Color ColourP1 { 
    get { return _ColourP1; } 
    set { 
     _ColourP1 = value; 
     OnChanged("ColourP1"); 
    } 
    } 
} 

Luego, su forma se vería así:

public Form1() { 
    InitializeComponent(); 

    Colours colours = new Colours(); 
    colours.PropertyChanged += colours_PropertyChanged; 
    this.propertyGrid1.SelectedObject = colours; 
} 

private void colours_PropertyChanged(object sender, PropertyChangedEventArgs e) { 
    this.propertyGrid1.Refresh(); 
} 

private void button1_Click(object sender, EventArgs e) { 
    ((Colours)this.propertyGrid1.SelectedObject).Reset(); 
} 
+0

Hola, gracias, eso es más o menos lo que ya tenía. Estaba más interesado en por qué la red de propiedad en sí no nota que la propiedad ha cambiado. Nada (es decir, el control PropertyGrid) se suscribe al evento "PropertyChanged". Claro ... Podría hacerlo yo mismo, como lo has hecho, pero ¿por qué? ¿Podría ser que el control PropertyGrid no tenga propiedades vinculadas, por lo que no escucha el evento INotifyPropertyChanged? –

4

Pasé por esta cuestión al tratar de recordar lo que solía utilizar y pensé que podría ser útil para otros.

Puede usar el atributo [RefreshProperties] para desencadenar actualizaciones en la cuadrícula de propiedades.

por ejemplo:

[RefreshProperties(RefreshProperties.All)] 
    public int MyProperty{ get; set; } 
Cuestiones relacionadas