mars
2007
L’attribut DefaultValue permet, comme son nom l’indique, de définir la valeur par défaut d’une propriété. Le problème, c’est que cette valeur doit être une constante, ce qui limite pas mal (en fait, il y a une surcharge du constructeur, qui prend un type et un string en paramètres, que nous verrons tout à l’heure). Impossible de définir une DefaultValue sur une propriété de type T (where T : class) comme on dirait avec les génériques sauf pour lui mettre null. Même sur certains ValueType, on a le problème (ex : Color). On ne peut, en effet, pas, à ma connaissance, définir de constante type Color. Cela pose le problème suivant : imaginons que nous avons défini une BackColor par défaut pour un contrôle. Du coup, comme on n’a pas de DefaultValue, la couleur est renseignée dans le .designer, du coup, si on veut en changer, il faut en changer partout.
En fait, il y a une parade. Prenons l’exemple d’une Combo pour laquelle on voudrait définir une propriété ReadOnly :
{
private bool _shouldSerializeBackColor;
public override Color BackColor
{
get
{
if (_shouldSerializeBackColor)
return base.BackColor;
if (_readOnly)
return SystemColors.Control;
return SystemColors.Window;
}
set
{
base.BackColor = value;
_shouldSerializeBackColor = true;
}
}
private bool _readOnly;
[DefaultValue(false)]
public bool ReadOnly
{
get { return _readOnly; }
set
{
_readOnly = value;
Refresh();
}
}
}
Ainsi, la couleur pour la classe Control reste Color.Empty. Donc la couleur n’est pas enregistrée dans le .designer.
Cependant, le problème est toujours valable pour une nouvelle propriété. Quand vous avez une propriété nommée « A » et que vous lançait un évènement « AChanged » sur le set de A, les contrôles bindés à A sont automatiquement raffraîchis. (En C# 2.0, l’interface INotifyPropertyChanged permet de ne créer qu’un seul évènement pour toutes les propriétés.) De la même façon, pour initialiser la valeur par défaut d’une propriété, il suffit d’écrire deux méthodes :
private static readonly Color _defaultTestColor = Color.Red;
public Color Test
{
get
{
if (_test == Color.Empty)
return _defaultTestColor;
return _test;
}
set { _test = value; }
}
public bool ShouldSerializeTest()
{
return _test != Color.Empty;
}
public void ResetTest()
{
_test = Color.Empty;
}
J’ignore si une interface permet de généraliser ça. Vous trouverez plus d’infos sur le site suivant.
Pour une propriété de type Color, il y a une feinte :
[DefaultValue(typeof(Color), "Red")]
ou
[DefaultValue(typeof(Color), "18,11,81")]
pour les couleurs non nommées.
Cela peut être, à priori (je n’ai pas encore testé), généralisé en utilisant l’attribut TypeConverter sur la classe.