16. februar 2005 - 00:20Der er
45 kommentarer og 1 løsning
Data i ListBox.Items bliver ødelagt
Hej
Jeg har et problem som jeg simpelthen ikke kan gennemskue, og kan ikke finde nogen som helst løsning nogle steder.
Det er således at jeg har implementeret min egen FontListBox som nedarver fra den oprindelige ListBox control, men med nogle ændringer i OnMeasureItem, OnResize og OnDrawItem for at kunne vise de data jeg ønsker.
Datane er fonte - dvs. navnet på fonten efterfulgt af en tekststreng vist med den font.
Jeg benytter denne FontListBox til to formål - enten at vise de i systemet installerede fonte eller at vise fonte liggende i en brugerspecificeret mappe.
Når jeg viser systemfonte så virker det perfekt. Alt tegnes korrekt og ingen problemer der.
MEN når jeg indlæser fonte fra et custom bibliotek, via PrivateFontCollection, så sker der underlige ting og sager. Hvis jeg resizer mit vindue (og derved også controllen), eller overlapper med andre vinduer (umiddelbart så er det ved Paint at det mystiske sker), så bliver mine data, altså ListBox.Items ødelagt - og jeg får ArgumentException i navnefeltet på fontene i Items.
Det giver for mig ingen mening, og har prøvet alverdens mulige løsninger og hacks, men intet hjælper. Det pudsige er at den tegner controlen ganske fint til at starte med, men så på et vilkårligt tidspunkt hvis man f.eks. resizer controlen, så dør datane.
Håber at der er nogle der har forslag til hvorledes jeg kan løse dette - evt. hvordan jeg kan finde kilden til skidtet - ja hvad som helst!
Ps. Bare sig til hvis i har brug for nærmere præcisering eller kodestykker.
er der på noget som helst tidspunkt du ændrer på din items-collection efter at du har loadet alle fontene ind fra en mappe?
Går ud fra at du enumererer igennem den en del gange i forbindelse med tegningen af din ListBox. En mulighed var at lave en Clone af din ItemsCollection inden du enumererer igennem den for at være sikker på at den hele tiden er konsistens.
Ja, du har ret i at jeg ittererer igennem mine items ret ofte - åbenlyst når jeg skal tegne dem. Jeg er dog imidlertid også nødsaget til at fjerne alle items og genindsætte dem hver gang jeg resizer controlen - for ellers bliver OnMeasureItem ikke kaldt, og derved kan controlen tegnes forkert.
Til dette har jeg prøvet lidt forskelligt - tænkte nemlig det samme som dig - så derfor prøvede jeg at have en konsistent kopi af mine items liggende som jeg så bruger til at indsætte fra. Således at det ikke er de oprindelige items der indsættes, men derimod nogle tilsvarende items.
Og her er noget endnu mere pudsigt - også de items i min 'backup' collection ødelægges - så umiddelbart virker det ikke som en fejl i ListBox contolen, men noget der ganske enkelt sker med de Font objekter jeg laver ud fra filer...
Hmm, jeg ved ikke om det er helt sort det jeg skriver - men jeg værdsætter din hjælp.
med mindre at du laver en decideret DeepClone, er det de samme fontoboejcter der ligger i din Items Collection og "backup'en", da det kun er referencerne du kopierer.
Det virker da underligt at du skal fjerne alle dine objecter og indsætte dem igen. Kan du ikke bare kalde OnMeasureItem manuelt?
Backuppen og de oprindelige items er adskilt. De oprettes på to forskellige måder og to forskellige tidspunkter. Så der burde ikke være noget problem med at det blot er referencer der kopieres.
Mht. manuelt kald af OnMeasureItem - så virker det ikke umiddelbart til at det kan lade sig gøre. Eller anyway - det MeasureItemEventArg argument kaldet kræver, kan jeg ikke lige gennemskue hvor jeg skulle få fra i fald jeg ønsker at kalde OnMeasureItem(MeasureItemEventArgs) manuelt.
Men det er ikke umiddelbart koden til FontListBox'en den er gal med... For hvis jeg deaktivere alle mine overrides så crasher den stadig (og controlen bliver selvfølgelig tegnet forkert).
umiddelbart kan jeg dog hellerikke forstå hvorfor at du vil ændre højden på dine items når at listboxen bliver reziset... det skal jo have samme størrelse
Nej, de skal ikke have samme størrelse - pointen er at jeg gerne vil vise en streng - og i fald denne streng, tegnet med den givne font, er for lang til at kunne vises i sin fulde længde, da brydes den op - hvorved højden på Item'et naturligvis ændres. Så som bredden på ListBox'en ændres, så ændres Item's højde.
Ok, så prøv at tilføje en font, fra en fil, som du ikke har installeret i systemet. Mit virker nemlig også perfekt hvis det er fonts fra InstalledFontCollection() jeg bruger... men lige så snart jeg læser fonte ind som ikke er installeret, så dør den pludselig.
Og din OnResize virker stadig ikke for mig - sure, den bryder linierne, men den gør ikke pladsen højere i fald man ikke kan se hele linien efter bruddet...
FontFamily[] ffs = getFontCollection().Families; Font f = null;
foreach (FontFamily ff in ffs) { f = null;
try { f = checkFontStyle(ff); if (f != null) fontList.Items.Add(f); } catch { errors++; log("Unable to display font: " + ff.Name); } }
}
private FontCollection getFontCollection() { FontCollection fc; if (menuItemWindows.Checked) { fc = new InstalledFontCollection(); } else { PrivateFontCollection pfc = new PrivateFontCollection(); string[] files = Directory.GetFiles(folderBrowserDialog.SelectedPath); foreach (string file in files) { if (file.EndsWith(".ttf") || file.EndsWith(".fon")) { pfc.AddFontFile(file); } }
fc = pfc as FontCollection; } return fc; }
private Font checkFontStyle(FontFamily ff) { Font printFont = null; string style = comboBox1.SelectedItem.ToString(); int size = (int) numSize.Value;
switch (style) { case "Regular": if (ff.IsStyleAvailable(FontStyle.Regular)) printFont = new Font(ff, size, FontStyle.Regular); break;
case "Bold": if (ff.IsStyleAvailable(FontStyle.Bold)) printFont = new Font(ff, size, FontStyle.Bold); break;
case "Italic": if (ff.IsStyleAvailable(FontStyle.Italic)) printFont = new Font(ff, size, FontStyle.Italic); break; case "Bold + italic": if (ff.IsStyleAvailable(FontStyle.Bold | FontStyle.Italic)) printFont = new Font(ff, size, FontStyle.Bold | FontStyle.Italic); break; }
if (printFont == null) throw(new ArgumentException());
Ja - så langt er jeg også. Undskyld hvis jeg ikke har udtrykt mig klart nok, men det er det jeg har prøvet at komme frem til hele tiden :) Men en løsning - findes den?
det er okay... det er jo svært at snakke om et problem når kun den ene oplever det :)
jeg har nu kommet så langt, at det ikke er antallet af font-objecter det kommer an på, men antallet af gange OnDrawItem-funktionen bliver kørt. Ved godt det lyder åndsvagt, men hvis jeg f.eks. kun tilføjer et font-object, og hiver rundt med formen et par gange, så den skal gentegne kommer fejlen også
:) sådan... så fandt jeg ud af det... jo, det er semi-bug ;)
problemet ligger i, at Font-objecter bliver ved med at have en forbindelse til det PrivateFontCollection-object de til at starte med blev loaded ind i. Det betyder at når GC'en kan se at når dit pfc-object
PrivateFontCollection pfc = new PrivateFontCollection();
går ud af scope og bliver fjernet fra rammen, bliver alle dine font-objecter også nedlagt. Rimelig crappy, og løsningen på det er at sørge for dit pfc-object ikke går ud af scope, evt. ved at oprette den som field i den form Listboxen skal være i.
Helt officielt så elsker jeg dig af hele mit hjerte nu! ;)
Smid et svar så du kan få dine velfortjente point :)
Meget pudsigt - har tænkt på at det kunne være noget i den retning, altså at jeg havde et objekt som kom ud af scope, men havde ingen anelse om at fontobjekterne rent praktisk var knyttet til deres FontCollection...
Tydeligvis ikke :) Men endnu engang tak for hjælpen...
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.