C# - ListView kontrol, oszlopokhoz kapcsolódó gyorstippel

forráskód letöltése
Talán sokak számára ismert probléma, hogy a táblázatok adott oszlopainak szélessége nem minden esetben igazodik a leghosszabb elem szélességéhez. Ebben az esetben a felhasználó kényelmetlensége fokozódik, hiszen egy sokoszlopos táblázatnál kénytelen az oszlopszélességet manuálisan módosítani. Amennyiben a ListView kontrol View property-jét Details értékre választjuk, egy táblázat formájában jeleníthetjük meg a tárolt értékeket. A kontrol esetében szintén az imént vázolt problémába ütközünk. Cikkünkben elkészítünk egy kontrolt, mely kísérletet tesz a megoldásra úgy, hogy a hosszú oszlop-érték fölött mozgatva az egeret megjelenít egy gyorstippet az adott értékkel.
A mellékelt alkalmazásban az LVClient projekt mappájában található Products.xml állomány tartalmát jelenítjük meg a Form-ra helyezett, ListView osztályból származó kontrolunkban. A kontrol View property-jének értéke Details lesz, vagyis egy táblázatot látunk.
DataSet ds = new DataSet();
ds.ReadXml(Application.StartupPath + "\\Products.xml");
ListViewItem lvi = null;
string[] data = new string[3];
for(int i=0;i<ds.Tables[0].Rows.Count;i++)
{
  data[0] = ds.Tables[0].Rows[i]["ProductID"].ToString();
  ...  
  lvi = new ListViewItem(data);
  lvControl1.Items.Add(lvi);
}
A táblázat második oszlopában találhatók meg a termékneveket reprezentáló karakterláncok, melyek egy részének hossza meghaladja az aktuális oszlopszélességet, vagyis a karakterláncok végén – intelligens módon – három pont jelenik meg (utalva a túllógásra).
A megoldásban úgy járunk el, hogy egy gyorstipp ablakban jelenítjük meg a túllógó terméknevet akkor, ha az egér mutatója az adott elem fölött tartózkodik. Egyéb esetben természetesen nem jelenítünk meg semmit. Lássuk a kontrolunkat.
A kontrol legfontosabb jellemzője, hogy képes fogadni a Windows üzeneteket. Ezt a konstruktorában adhatjuk meg, a SetStyle metódus segítségével.
SetStyle(ControlStyles.EnableNotifyMessage, true);
Létrehoztunk továbbá egy eseménykezelő delegáltat egy saját paraméterosztállyal. Az esemény akkor keletkezik („sül el”), amikor a kontrol a Tooltip megjelenítésére utasító üzenetet kapja a rendszertől.
public delegate void ItemEventHandler(object sender, ItemEventArgs e);
protected event ItemEventHandler itemEvent;
A kontrol legfontosabb metódusa az OnNotifyMessage metódus, melyben kiértékeljük a kontrol által kapott üzeneteket. Amennyiben a kontrol a WM_NOTIFY üzenetet kapja, vagyis egy olyan üzenetet, mely valamilyen információt akar megszerezni a kontrollal kapcsolatban (jelen esetben az oszlop szélessége), akkor elindul a feldolgozás.
if (m.Msg == WM_NOTIFY)
{
  NMHDR n = (NMHDR)Marshal.PtrToStructure(m.LParam, typeof(NMHDR));
Az üzenet LParam paramétere egy struktúra, melynek a code nevű mezője hordoz számunkra lényeges információt. Ha ennek értéke TTN_NEEDTEXT, akkor kell megjeleníteni az adott elemhez kapcsolódó Tooltip-et.
  if (n.code == TTN_NEEDTEXT)
  {
    ShowText();
  }
}
A ShowText metódusban jön létre az esemény, melyet majd elkapunk a kliens-alkalmazásban és megjelenítjük a gyorstippet. A metódusban hívjuk meg a Test metódust, mely a SendMessage API metódussal egy üzenetet küld a kontrolnak, nevezetesen a LVM_SUBITEMHITTEST konstanssal, hogy megtudja az adott oszlop szélességét.
A metódus hívása után az IsTextHidden metódus segítségével kérdezzük le, hogy az adott oszlop szélessége nagyobb-e, mint az elem, mely fölött a mutató van. Amennyiben nem, akkor megjelenik a gyorstipp.
A kontrol egyéb metódusai a következők:
  • ColumnWidth: az adott oszlop szélességét adja vissza.
  • StringWidth: az egér által mutatott elem karakterláncának hosszát adja vissza.
  • GetRectangle: a mutatott elem befoglaló téglalapjának objektumát határozhatjuk meg vele.
A kliensalkalmazásban egyszerűen deklaráltunk egy eseménykezelőt a létrehozott eseményhez.
lvControl1.ItemEvent += new LVLibrary.LVControl.ItemEventHandler(lvControl1_ItemEvent);
A kezelőben megvizsgáljuk a paraméterként kapott objektum ItemTextInVisible property-jét. Amennyiben igaz, lekérdezzük a mutatott karakterláncot, melyet szintén egy property tartalmaz.
string s = lvControl1.Items[e.Item].SubItems[e.SubItem].Text;
A karakterláncot átadjuk a HandlingWord metódusunknak, mely a megfelelő formátumba hozza azt, és megjelenítjük a gyorstippet a Tooltip objektum felhasználásával.
toolTip1.SetToolTip(lvControl1, HandlingWord(s));
lastItem = e.Item;
lastSubItem = e.SubItem;
A művelet eredményeképpen feleslegessé tehető az oszlopok átméretezése.