[C#] Listbox met UserControl bug

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Ik kwam trouwens achter een hele rare bug in het .Net framework, het blijkt dat als je een ListBox hebt (een soort van ArrayList/List/Vector waar je objecten aan kunt toevogen en die de ToString() van dat object aan roept om de items te laten zien in een lijst). Niet over weg kan met objecten die inherritten van UserControl. Echt ontzettend wazig, je krijgt dan gewoon een lege regel, alsof de .ToString() niet wordt aangeroepen of "" returned.

Ik heb er zelfs een connect item over gemaakt, waar de bug confirmed is maar helaas niet opgelost gaat worden. De oplossing voor dit probleem was gewoon een object maken die niet inherit van UserControl en die als wrapper om je control heen te zetten.

Ik vraag me wel af waar dit door kwam, iemand had het over mogelijke problemen met reflection, maar ik snap het nog steeds niet helemaal. Je zou toch verwachten dat die ListBox alleen maar achter de schermen een List heeft (de niet generic versie) waar alles in gaat en bij het tekenen gewoon:
C#:
1
2
3
4
for (int i = 0; i < this.items.count; i++)
{
     this.draw(items[i].ToString()); //en nog iets met posities enzo
}


Hmm ik zou eigenlijk eens moeten kijken hoe die class in elkaar zit, ik geloof dat dat met ildasm kan ofzo? (Nooit geprobeerd).

Anyway voor meer info hier het connect item (hoeft/kan niet meer op gevote worden aangezien het non-priority is, maar dan staat er nog wat meer info en code voorbeelden bij).

http://connect.microsoft....ck.aspx?FeedbackID=473861

(over waarom ik dit wilde, ik had een mooie lijst controls waarvan je nieuwe instanties aan een andere lijst kon toevoegen en zo een beetje een editor had).

Edit: over manuals is er voor mij gewoon weinig wat MSDN kan overtreffen, zowel voorbeelden in meerdere talen als duidelijk wat een functie hoort te doen. De java documentatie vind ik altijd een beetje onoverzichtelijk, het is soms teveel op 1 pagina (op de MSDN heeft vaak elke methode een eigen pagina). De PHP docs vind ik opzich wel ok, maar die user comments zijn soms verradelijk, daar zou iets meer gemodereerd mogen worden.

[ Voor 11% gewijzigd door roy-t op 17-07-2009 14:58 ]

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 18:57
roy-t schreef op vrijdag 17 juli 2009 @ 14:56:
Hmm ik zou eigenlijk eens moeten kijken hoe die class in elkaar zit, ik geloof dat dat met ildasm kan ofzo? (Nooit geprobeerd).
Ik denk dat het makkelijker / handiger zou zijn als je dat met Reflector doet. :) (Vroeger van Lutz Roeder, nu van Redgate).

Ik weet echter niet of je daar zoveel wijzer zult mee zijn.
Volgens mij is de .NET ListBox control een wrapper rond de Windows Listbox control (net zoals andere controls).

[ Voor 17% gewijzigd door whoami op 17-07-2009 15:06 ]

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • Canaria
  • Registratie: Oktober 2001
  • Niet online

Canaria

4313-3581-4704

Wat gebeurt er als je ToString() van de UserControl override door er een constante in te zetten? Pakt de ListBox hem dan wel?

Apparticle SharePoint | Apps | Articles


Acties:
  • 0 Henk 'm!

  • whoami
  • Registratie: December 2000
  • Laatst online: 18:57
Canaria schreef op vrijdag 17 juli 2009 @ 15:09:
[...]

Wat gebeurt er als je ToString() van de UserControl override door er een constante in te zetten? Pakt de ListBox hem dan wel?
Neen.

Volgens mij is dit trouwens hetgeen uitgevoerd wordt om een item te 'drawen':

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void WmReflectDrawItem(ref Message m)
{
    NativeMethods.DRAWITEMSTRUCT lParam = (NativeMethods.DRAWITEMSTRUCT) m.GetLParam(typeof(NativeMethods.DRAWITEMSTRUCT));
    IntPtr hDC = lParam.hDC;
    IntPtr handle = Control.SetUpPalette(hDC, false, false);
    try
    {
        using (Graphics graphics = Graphics.FromHdcInternal(hDC))
        {
            Rectangle rect = Rectangle.FromLTRB(lParam.rcItem.left, lParam.rcItem.top, lParam.rcItem.right, lParam.rcItem.bottom);
            if (this.HorizontalScrollbar)
            {
                if (this.MultiColumn)
                {
                    rect.Width = Math.Max(this.ColumnWidth, rect.Width);
                }
                else
                {
                    rect.Width = Math.Max(this.MaxItemWidth, rect.Width);
                }
            }
            this.OnDrawItem(new DrawItemEventArgs(graphics, this.Font, rect, lParam.itemID, (DrawItemState) lParam.itemState, this.ForeColor, this.BackColor));
        }
    }
    finally
    {
        if (handle != IntPtr.Zero)
        {
            SafeNativeMethods.SelectPalette(new HandleRef(null, hDC), new HandleRef(null, handle), 0);
        }
    }
    m.Result = (IntPtr) 1;
}

https://fgheysels.github.io/


Acties:
  • 0 Henk 'm!

  • roy-t
  • Registratie: Oktober 2004
  • Laatst online: 08-09 11:33
Canaria schreef op vrijdag 17 juli 2009 @ 15:09:
[...]

Wat gebeurt er als je ToString() van de UserControl override door er een constante in te zetten? Pakt de ListBox hem dan wel?
Helaas gebeurt er dan helemaal niets (zie ook code voorbeeld @ connect).
whoami schreef op vrijdag 17 juli 2009 @ 15:13:
[...]

Neen.

Volgens mij is dit trouwens hetgeen uitgevoerd wordt om een item te 'drawen':

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
private void WmReflectDrawItem(ref Message m)
{
    NativeMethods.DRAWITEMSTRUCT lParam = (NativeMethods.DRAWITEMSTRUCT) m.GetLParam(typeof(NativeMethods.DRAWITEMSTRUCT));
    IntPtr hDC = lParam.hDC;
    IntPtr handle = Control.SetUpPalette(hDC, false, false);
    try
    {
        using (Graphics graphics = Graphics.FromHdcInternal(hDC))
        {
            Rectangle rect = Rectangle.FromLTRB(lParam.rcItem.left, lParam.rcItem.top, lParam.rcItem.right, lParam.rcItem.bottom);
            if (this.HorizontalScrollbar)
            {
                if (this.MultiColumn)
                {
                    rect.Width = Math.Max(this.ColumnWidth, rect.Width);
                }
                else
                {
                    rect.Width = Math.Max(this.MaxItemWidth, rect.Width);
                }
            }
            this.OnDrawItem(new DrawItemEventArgs(graphics, this.Font, rect, lParam.itemID, (DrawItemState) lParam.itemState, this.ForeColor, this.BackColor));
        }
    }
    finally
    {
        if (handle != IntPtr.Zero)
        {
            SafeNativeMethods.SelectPalette(new HandleRef(null, hDC), new HandleRef(null, handle), 0);
        }
    }
    m.Result = (IntPtr) 1;
}
Hmm ik zie daar niets in wat er voor zou zorgen dat sommige speciale objecten (usercontrols) het niet zouden doen, hmm zo vreemd!

~ Mijn prog blog!


Acties:
  • 0 Henk 'm!

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

Die code hierboven heeft er niets mee te maken.

Als het dan een IComponent is dan doet .NET geen ToString maar checkt hij de Name van de Site van die Component.

En aangezien bij een simpele Usercontrol er geen site bestaat is die name ook leeg, en dan krijg je een lege regel.

[ Voor 26% gewijzigd door Snake op 05-08-2009 16:59 ]

Going for adventure, lots of sun and a convertible! | GMT-8


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Dan zou je dus eventueel gewoon de Name van de Site kunnen zetten. Name van ISite heeft ook gewoon een setter: http://msdn.microsoft.com...nentmodel.isite.name.aspx

C#:
1
usercontrol.Site.Name = usercontrol.ToString();

Of zelf een implementatie van Site maken die bij name altijd parentControl.ToString() returnt.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • HawVer
  • Registratie: Februari 2002
  • Laatst online: 12:40
roy-t schreef op vrijdag 17 juli 2009 @ 14:56:
Hmm ik zou eigenlijk eens moeten kijken hoe die class in elkaar zit, ik geloof dat dat met ildasm kan ofzo? (Nooit geprobeerd).
Je kunt de source van .NET in duiken als je wil: :P

http://weblogs.asp.net/sc...-framework-libraries.aspx

http://hawvie.deviantart.com/


Acties:
  • 0 Henk 'm!

  • Snake
  • Registratie: Juli 2005
  • Laatst online: 07-03-2024

Snake

Los Angeles, CA, USA

Woy schreef op woensdag 05 augustus 2009 @ 17:06:
Dan zou je dus eventueel gewoon de Name van de Site kunnen zetten. Name van ISite heeft ook gewoon een setter: http://msdn.microsoft.com...nentmodel.isite.name.aspx

C#:
1
usercontrol.Site.Name = usercontrol.ToString();
Neen dan krijg je een NullPointerException helaas.
Of zelf een implementatie van Site maken die bij name altijd parentControl.ToString() returnt.
Dat is goed mogelijk ja.
Zo heb ik het ook 'ontdekt'.

[ Voor 7% gewijzigd door Snake op 06-08-2009 15:56 ]

Going for adventure, lots of sun and a convertible! | GMT-8


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 06:48

Sebazzz

3dp

Wat je ook nog kan doen is handmatig de items tekenen, door middel van de DrawMode op OwnerDraw te zetten. Je kan dan zelf handmatig de .ToString() aanroepen of andere methodes aanroepen als je dat zou willen. Alleen zal een zelf-drawn er niet zo snel even mooi uitzien als dat het OS het doet en het is duurder. Het event en de .ToString dus ook wordt iedere keer aangeroepen, terwijl als het OS het doet de waarden van de lijstobjecten gecached worden.

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

  • IceM
  • Registratie: Juni 2003
  • Laatst online: 11-09 20:35
Is er eigenlijk een vraag verbonden aan dit topic of wat is precies het doel van deze thread? Als je een simpele workaround wilt hebben dan kun je toch vrij makkelijk iets van een ControlItem klasse maken waarin je je usercontrol opslaat en de tostring functie in override zodat hij wel het juiste naampje terug geeft?

...


Acties:
  • 0 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 06:48

Sebazzz

3dp

Doel van dit topic? Logisch toch, mede .NETters vragen of het vermoeden juist is, ze ervan verwittigen, en workarounds posten. Mag eigenlijk wel meer in PRG m.i. :)

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]

Pagina: 1