C# - TreeView egyedi megjelenítése egyedi adatokkal

forráskód letöltése
Készítsünk olyan megjelenítésű TreeView kontrolt, melyben minden elemnél egy-egy egyedi értékű adatot tárolhatunk, jeleníthetünk meg ráadásul ezt is egyedi módon.
A megvalósításhoz szükség lesz arra, hogy a TreeView-ban megjelenő egyedi adatot saját magunk rajzoljuk ki, így viszont lehetőségünk van arra is, hogy bármilyen formát öltsön ez a megjelenítést, ami lehet szöveg, de akár képeket is használhatunk, vagy bármi más eszközt, amit csak a GDI+ lehetővé tesz.
Minden TreeNode képes arra, hogy egy egyedi objektumot tároljuk el, mely tetszőleges típusú adat lehet, akár egy összetett osztály is, mivel a tárolás Object típusban történik. Ezt a tárolást a Tag property végzi, melyben most véletlenszerű számokat helyezünk el.
        t = new TreeNode("Node "+i.ToString());
        t.Tag = r.Next(1000);
A megoldáshoz felül kell írnunk a Form ablakkezelő függvényét a WndProc-ot. Mivel a megvalósítás során kénytelenek leszünk pointereket is használni, így meg kell jelölnünk a függvény nem biztonságosként az unsafe kulcsszó használatával.
    unsafe protected override void WndProc(ref Message m)
    {
      switch (m.Msg)
      {
Ha a WM_NOTIFY üzenetet kapja alkalmazásunk, akkor kell ellenőriznünk, hogy az a TreeView újrarajzolása vált-e szükségessé, amennyiben egy így lenne, akkor hívjuk meg saját TreeViewPaint nevű függvényünket, hogy Tag property-ben tárolt számok is megjelenítésre kerüljenek.
        case Win32.WM_NOTIFY:
          lp=(Win32.NMHDR*)m.LParam.ToPointer();        
          if (lp->code == Win32.NM_CUSTOMDRAW)  
          {
            lp2=(Win32.NMCUSTOMDRAW*)m.LParam.ToPointer();
            if (lp2->dwDrawStage==Win32.CDDS_ITEMPREPAINT)
            {          
              base.WndProc(ref m);
              TreeViewPaint(ref m);
              m.Result = IntPtr.Zero;            
              return;
            }
            ...
A TreeViewPaint függvényben létrehozunk egy Graphics osztályt, mely képes a TreeView területére rajzolni.
    unsafe public void TreeViewPaint(ref Message m)
    {
      System.Drawing.Graphics g;
      g=Graphics.FromHwnd(treeView1.Handle);                    
      ...
Ezt követően meghatározzuk, hogy melyik elemet is kell aktuálisan megjeleníteni a TreeView-n belül.
      cd=(Win32.NMCUSTOMDRAW*)m.LParam.ToPointer();
      node=this.treeView1.GetNodeAt((int)cd->x1+1, (int)cd->y1+1);
Majd kiszámítjuk azt az x, y koordinátát, ahová a saját adatunk kerülhet. Ez minden esetben a TreeView adott eleme után következik, annak jobb oldalán.
      x=cd->x1+node.Bounds.X+node.Bounds.Width+5;
      y=cd->y1; 
Megpróbáljuk beolvasni a Tag property-be tárolt számot, majd a DrawString függvénnyel elvégezzük a kirajzolást.
      try
      {
        s="[" +node.Tag.ToString() +"]";
      }
      catch
      {
      }
      g.DrawString(s, treeView1.Font, new SolidBrush(Color.Red), x, y, StringFormat.GenericTypographic);    
    }
Mivel alkalmazásunkban pointereket használunk és az unsafe jelzőt is alkalmazzuk, így szükségessé válik még egy beállítás, hogy programunk lefordítható legyen. Ehhez keressük elő a Solution Explorer-ben az aktuálisa projektet, majd a jobb egér gombra megjelenő menüből válasszuk a Properties menüpontot. A megjelenő ablakból a Configuration Properties - Build elemnél az Allow unsafe code blocks tulajdonságot állítsuk igazra.