Zoek

Uitgebreid zoeken Artikelen per auteur

  

Eigenschappen van een Verzameling

Eigenschappen van een Verzameling

Introductie

Soms valt je opeens iets op terwijl het gewoon binnen handbereik ligt, zo ook met Visual Studio 2005. Al de hele tijd gebruiken we een nieuwe eigenschap van controls genaamd Anchor, terwijl deze eigenlijk vrij uniek is ten opzichte van alle andere eigenschappen. Kijk alleen maar eens naar de editor (figuur 1) in het Properties window. Hebt u die ook ergens anders in de IDE gezien?

Fig. 1:De Anchor eigenschap heeft een unieke editor

De anchor eigenschap is overigens ontzettend handig: een child control kan binnen een ‘container’ met de randen verankerd worden zodat het herschalen van de container ook de vorm van het child control dynamisch aanpast. We kunnen opgeven: Left, Top, Right, Bottom of juist None, maar ook een willekeurige combinatie van de eerste vier is mogelijk. De instelling gedraagt zich dus als een soort van verzameling van individuele keuzes uit een lijst van vooraf bekende mogelijkheden.

Voor de lezers met een Borland Delphi achtergrond komt dit vaag bekend voor. In die taal is het mogelijk een verzameling van enumeratie constanten samen te stellen (Set Of). De Anchor property blijkt op dezelfde manier te werken!

In dit artikel duiken we wat dieper in op een dergelijke eigenschap die een verzameling van keuzes representeert en we zullen ook zelf een editor voor de eigenschap creëren.

Het FlagsAttribute attribuut

Basis voor de verzameling met te selecteren waarden is een normale enumeratie-constanten-lijst, maar met een paar opvallende aanpassingen:

[FlagsAttribute]
public enum PropSet
{
  None = 0,
  Een = 1,
  Twee = 2,
  Drie = 4,
  Vier = 8,
}

Ten eerste staat boven de enum een attribuut: FlagsAttribute, ten teken dat meerdere waarden samen geselecteerd kunnen worden (bitwise combination). Ook hebben alle elementen een integer waarde gelijk aan 2n . De geselecteerde enumeratie constanten moeten straks gezamenlijk in één waarde onthouden worden. Door de verschillende constanten gelijk te houden aan unieke 2n waarden, geeft iedere combinatie ook een unieke sommatie als eindgetal.

Als laatste ziet u dat er een extra veld ‘None’ met de waarde nul is opgenomen. Deze representeert de situatie dat er geen enkele element gekozen is… De reeks 0, 1, 2, 4, 8, enz. is het handelsmerk van een enum verzameling.

Een enumeratieverzameling property zelf is recht-toe-recht-aan:

private PropSet myVar;
public PropSet MyProperty
{
  get { return myVar; }
  set { myVar = value; }
}

In eerste instantie is dit alles wat betreft de eigenschap. De eigenschap accepteert nu iedere deelverzameling van de enum elementen. Kijk maar eens naar de nu al beschikbare property editor (figuur 2):

Fig. 2: De standaard 'editor' voor een verzameling

Via de dropdownlist kan helaas maar één waarde gekozen worden, maar in het tekstveld zelf kan iedere combinatie van elementen ingevoerd worden (gescheiden door komma’s) bv. een, twee. Dan wordt de combinatie van Een, Twee gerepresenteerd.

Vul in dit veld nu ook eens een waarde in tussen de nul en vijftien. Bij de waarde zes worden Twee en Drie gekozen. Met acht erbij, Veertien, wordt ook Vier gekozen. De eigenschap vertegenwoordigt dus eigenlijk een integer getal, samengesteld uit de som van de afzonderlijke enumeratie constanten!

Vergelijk dit nu eens met de Anchor property uit figuur 1).

Ook hier kan als alternatieve invoer een integer waarde ingevoerd worden. De waarde Twaalf resulteert in de combinatie van Left en Right.

Maar de dropdownlist van de Anchor eigenschap ziet er toch opvallend anders uit! Er kan bij deze alternatieve invoer nu wel een combinatie gemaakt worden van meerdere elementen. Voordat we ingaan op de vraag of wij ook zo’n property editor kunnen construeren, gaan we eerst eens met de ingevoerde waarden spelen.

Kies bij ons voorbeeld MyProperty eens de waarden Een en Drie. De eigenschap heeft dus de waarde integer waarde vijf (= 1 + 4):

MessageBox.Show(customControl11.MyProperty.ToString());

De ToString() geeft netjes “Een, Drie” terug. Maar hoe achterhaal ik nu de werkelijk geselecteerde elementen?

Validatie van een verzameling van enumeratie constanten

Uitgangspunt bij het achterhalen van de geselecteerde elementen is dat de elementen bits-gewijs bij elkaar ‘opgeteld’ worden, en wel met behulp van binaire operators: AND, OR en Exclusieve OR (XOR).

Bij hetzelfde voorbeeld (waarde 5) geeft

(customControl11.MyProperty ==
  (PropSet.Een | PropSet.Twee | PropSet.Drie) )
// False

de waarde False terug. De gekozen verzameling bestaan dus niet uit Een, Twee en Drie.

Maar de vergelijking:

((customControl11.MyProperty & PropSet.Een) ==
  (PropSet.Een))
// True

geeft wel True terug. Constante Een zit dus in de gekozen verzameling.

Kijk ook eens naar de volgende situaties:

((customControl11.MyProperty & PropSet.Twee)
   == (PropSet.Twee))  // False
((customControl11.MyProperty & PropSet.Drie) ==
   (PropSet.Drie))  // True
((customControl11.MyProperty & PropSet.Vier) ==
   (PropSet.Vier))  // False

Dit kan ook in een static functie gevat worden:

public class PropertySetHelper
{
  public static bool InEnumSet(
    PropSet set, PropSet valuesSubSet)
  {
    bool result =
      ((set & valuesSubSet) == valuesSubSet);
    return result;
  }
}

De notatie is dan:

(PropertySetHelper.InEnumSet(
  customControl11.MyProperty, PropSet.Drie))   // True

U had zeker al gezien dat InEnumSet een attribuut ‘set’ en een attribuut ‘valuesSubSet’ bevat. ValuesSubSet is meervoud, dus er kan van de gekozen verzameling ook getest worden op een deelverzameling met meerdere elementen.

We voegen nu Vier toe aan de te testen verzameling. Deze bevat nu dus Een, Drie en Vier. Om te testen of de geselecteerde verzameling oa. Drie en Vier bevat, kan de volgende notatie gebruikt worden:

(PropertySetHelper.InEnumSet(
   customControl11.MyProperty,
   PropSet.Drie | PropSet.Vier))
// true

Het resultaat is True.

Helaas werkt dit ook correct voor een lege verzameling… want iedere verzameling bevat altijd een lege verzameling, dus deze functie geeft bij het testen op een lege verzameling dus ALTIJD een true terug (zie ook http://nl.wikipedia.org/wiki/Lege_verzameling).

Dus testen op een lege verzameling moet dus gewoon met de volgende vergelijking:

(customControl11.MyProperty == PropSet.None)

UITypeEditor voor design-time property editors

We hebben dus gezien dat een verzameling van enum elementen zich gezamenlijk als een getal laat representeren, maar dat het ook als een echte verzameling via binaire operatoren te manipuleren is. In de IDE designer hebben we hier wat minder aan. We hadden al gezien dat de standaard DropDownList editor slechts één element accepteert en we willen juist een gave editor zoals bij Anchors.

Dit is mogelijk en is zelfs redelijk triviaal! We gaan nu zelf een alternatieve Property Editor koppelen en toepassen.

Overigens heeft Microsoft zelf niet altijd de moeite genomen om fraaie editors te ontwerpen. Zo heeft de eigenschap NotifyFilter van de veel gebruikte FileSystemWatcher geen eigen editor maar het invoeren van een getal geeft hetzelfde resultaat. Ook komt None niet voor in het rijtje enum waarden. Wellicht is het niet relevant om te luisteren naar… niks.

Als uitgangspunt voor onze eigen editor nemen we een eenvoudige NumericUpDown. Deze kan een getal smakelijk aanbieden met van die pijltjes erbij. Dit geeft de meest eenvoudige oplossing voor ‘multiselect’ (zie figuur 3 voor het gewenste resultaat)

Fig. 3: Onze property met een nieuwe editor

Er resten ons nu twee stappen: eerst het gecombineerd bouwen en registreren van de aan te roepen editor en daarna het koppelen van de specifieke editor aan onze eigen property.

Stap 1: Bouw en registratie van onze eigen editor

Editors in de Properties Windows zijn afgeleid van UiTypeEditor. We gaan hier dus ook onze eigen editor van afgeleiden:

using System;
using System.Drawing.Design;
using System.ComponentModel;
using System.Windows.Forms.Design;
using System.Windows.Forms;

namespace TestPropertySet
{
  class MultiSetMembersEditor : UITypeEditor
  {
    …
  }
}

Een afgeleide van UiTypeEditor moet twee methoden implementeren. De eenvoudigste is GetEditStyle. Vertel hier de IDE welke type editor getoond gaat worden:

public override UITypeEditorEditStyle
  GetEditStyle(ITypeDescriptorContext context)
{
  return UITypeEditorEditStyle.DropDown;
}

Omdat we een dropdownlist willen gaan tonen retourneren we UITypeEditorEditStyle.DropDown. Als we voor Modal gekozen hadden, zou in het property window de drie puntjes (ellipsis (…)) getoond worden. Een modaal scherm zou dan die keuze moeten ondersteunen…

De tweede methode is iets lastiger maar niet onoverkomelijk. Deze methode wordt uitgevoerd als de ontwikkelaar de dropdown benadert. Deze methode heet EditValue.

public override object EditValue(
  ITypeDescriptorContext context,
  IServiceProvider provider,
  object value)
{
  SetMember result = SetMember.None;

  if (context != null
    && context.Instance != null
    && provider != null)
  {
    IWindowsFormsEditorService editorService =
      (IWindowsFormsEditorService)provider.
         GetService(typeof(IWindowsFormsEditorService));

    if (editorService != null)
    {
      NumericUpDown nud = new NumericUpDown();
      nud.Minimum = 0;
      nud.Maximum = (((int)SetMember.Vier) * 2) - 1;
      SetMember enumValue = (SetMember)value;
      nud.Value = (int)enumValue;

      editorService.DropDownControl(nud);

      result = (SetMember)nud.Value;
    }
  }
  return result;
}

Het geretourneerde object (onze nieuw aangemaakte numeric up/down) representeert de door de ontwikkelaar voorheen gekozen waarde. Maar voordat we zover zijn, vragen we eerst toegang tot een Editor service. Daarna construeren we de te tonen NumericUpDown  en vullen we daar de huidige waarde in. Daarna geven we de NumericUpDown door aan de verkregen service. Merk op dat tenslotte de door de gebruiker gekozen waarde weer verkregen en doorgegeven wordt.

Stap 2: Koppelen van de nieuwe editor aan onze property

Is dit dus alles? Bijna, de eigen editor is gebouwd en klaar voor gebruik. Als laatste moet deze aan de nieuwe eigenschap MyProperty gekoppeld worden. Hierbij volstaat het toekennen van het attribuut Editor.

public partial class CustomControl1 : Control
{
  …

  [Editor(typeof(MultiSetMembersEditor), typeof(UITypeEditor))]
  public etMember MyProperty
  {
    …
  }
}

De IDE zal dan via reflection de editor aan de property koppelen. Dat is dus vrij triviaal.

De MultiSetMembersEditor wordt nu als nieuwe UITypeEditor toegekend. Als de ontwikkelaar nu de dropdown kiest, zal de NumericUpDown getoond worden. De huidige waarde is ingevuld en nadat de ontwikkelaar een nieuwe keuze heeft gemaakt, zal deze getoond worden. Bij het invullen van b.v. integer vijftien zullen naderhand alle vier de enumeratie constanten geselecteerd zijn (zie figuur 4).

Fig. 4: De nieuwe editor na keuze van een nieuwe verzameling

Conclusie

Hoewel toepassingen van een FlagsAttribute eigenschap tot op heden redelijk uniek zijn, vind ik het een heel aardige aanvulling bij het bouwen van nieuwe controls en componenten. Zoals in dit artikel gedemonstreerd is, kan een verzameling enumeratie constanten snel en eenvoudig toegepast en uitgevraagd worden en is ook een specifieke editor met een minimale inspanning te bouwen.

Veel succes!

Commentaar van anderen:
watch op 9-7-2010 om 9:44
How many peopleChanel replica can promise he or she will love one forever and really Chloe replicaact it out? When one has beenreplica Cartier making efforts for many years but there is replica Celine still no achievement,replica Chanel who will still wait for you?chopard replica Finally we understand Christian Dior replicathat we can confront that one who you loves replica Mulberry handbags love you, but Piaget handbags can confront thatreplica Dior hangdbags who has been loving you replica Dolce & Gabbana hangdbags for many years leaves you. That kind ofreplica Dooney & Bourke hangdbags pride and happiness disappear.You can get a range of Longines for sale here. Please cherish people around who love you quietly. MaybeLouis Vuitton for salesome day you will find that it is youself who can not leave him or her Maurice Lacroix for salewhen he or she leaves.
replica handbags op 16-7-2010 om 9:50
If you have designer handbagsthe ability to choose thechanel replica right style from thousands of designer bags in the replica balenciagamarket to fit your needs and bottega veneta handbagsoccasions, you will be quiteswiss watches of the ordinary people and enjoyBurberry replica the great feeling they couldn’tGraham for sale imagine.The Instrumento NovantatreFerrari for sale offers the choice between a gold oris for saleand steel version, optionally Audemars Piguet for saledecorated with gemstones.replica handbags The model has joined both the ladies'Mulberry replica and gentlemen's de Grisogono bally handbagscollections. The curved sapphirereplica croum case back, featuring the corporate crestreplica Christian Dior, demonstrates the workings, the movement andreplica ebel its oscillating weight, both Cheap Handbags blackened by the PVD process. With a beautiful cheap fendi handbagson your shoulder, you could walk proudly in the hermes replica handbagsstreet and people will eye you with admirationburberry replica handbags.
fasfaf fasfafaf op 28-7-2010 om 4:52
Tiffany jewelry manufacturers directory,cheap jewelry - lots of registered importers and exporters. Cheap tiffany jewelry manufacturers, Tiffany & co jewelry suppliers, tiffany jewelry wholesales, Tiffany Watches,exporters, sellers, traders and gold tiffany jewelry Distributors from China and around the world at www.goldtiffanyjewelry.com Tiffany jewelry exporters, Tiffany Accessories, Tiffany Bangles, Tiffany Bracelet, Discont Tiffany Bracelet, Discount Tiffany Cufflinks, Fashion Tiffany Earring, Tiffany Necklaces , Discount Tiffany Necklaces, Tiffany Rings, Tiffany Watches
Geef feedback:
Verzend Commentaar