CatZMedlem sedan jan. 20022 440 inlägg Jag och kollegan sitter och håller på att bli tokiga på att inte kunna binda en IList eller List till en DataGridView i en forms application.
Hur är det meningen att man ska göra? Vi har läst på alla möjliga ställen om bindinglist och bindingsource men lyckas inte...
hur *** ska man göra? :e
CompusaMedlem sedan jan. 20023 327 inlägg Jag har också varit där och snurrat :e
Här kommer förklaringen/exempel.
Detta fungerar inte
[B]I[/B]List<Customer> customers = new List<Customer>(); // IList
...
myDataGridView.DataSource = customers;
Detta fungerar
List<Customer> customers = new List<Customer>(); // List
...
myDataGridView.DataSource = customers;
Eller detta
[B]I[/B]List<Customer> customers = new List<Customer>(); // IList
...
myDataGridView.DataSource = customers.ToList();
Varför?
1. The DataGridView control supports the standard Windows Forms data binding model, so it will bind to instances of classes described in the following list:
· Any class that implements the IList interface, including one-dimensional arrays.
· Any class that implements the IListSource interface, such as the DataTable and DataSet classes.
· Any class that implements the IBindingList interface, such as the BindingList<(Of <(T>)>) class.
· Any class that implements the IBindingListView interface, such as the BindingSource class.
IList doesn’t implement any of the interfaces described above, that’s the reason that your DataGridView doesn’t display anything.
Du kan med andra ord inte binda mot ett objekt som är av en interface-typ (IList), utan du måste binda mot ett objekt som är av en implementations-typ (List).
CatZMedlem sedan jan. 20022 440 inlägg Tyvärr är det inte riktigt så enkelt, i vårt fall har vi en struct som får sina värden från ett gammalt vb-program.
Eftersom structen måste se ut som den gör (vi kan även ha den som en klass) men vi kan inte lägga till några konstruktorer eftersom vi får fel vid inläsningen av data då.
Du måste instantiera en lista och alla rader för att kunna använda den som datasource till tex en datagridview. Eftersom vi inte kan göra det så finns värdena där och vi har som alternativ att antingen krånga med datatables (väldigt omständigt) eller skapa någon slags factory till de klasserna. Jag sitter fortfarande och funderar på vilket som blir enklast att underhålla och förstå. För tillfället så loopar vi igenom allting för att få in det i våra winforms kontroller och det känns riktigt b men jag har inte lyckats få till någon annan lösning än.
Lösningen på min frågeställning postar jag här lite senare!
cokMedlem sedan dec. 2005664 inlägg Hur läser ni in datat från det externa prgrammet då?
GladhMedlem sedan maj 20012 812 inlägg
catz skrev:
Du måste instantiera en lista och alla rader för att kunna använda den som datasource till tex en datagridview. Eftersom vi inte kan göra det så finns värdena där och vi har som alternativ att antingen krånga med datatables (väldigt omständigt) eller skapa någon slags factory till de klasserna. Jag sitter fortfarande och funderar på vilket som blir enklast att underhålla och förstå. För tillfället så loopar vi igenom allting för att få in det i våra winforms kontroller och det känns riktigt b men jag har inte lyckats få till någon annan lösning än.
Få se om jag hänger med här...
Du har en lista med structer som inte kan innehålla en konstruktor, men för att binda listan till en datagridview så måste struterna ha en konstruktor annars fungerar det inte, rätt?
Om det är fallet så hade jag helt enkelt skapat mig en "wrapperklass" som hade motsvarat er struct, omvandlat din lista av structer till en lista av wrapperklasser och bundit dessa till datagridviewn. Det enklast sättet att mappa mellan structen och wrapperklassen blir att wrapperklassen innehåller en struct och alla properties i wrapperklassen pekar ner på samma property i structen.
- M
CatZMedlem sedan jan. 20022 440 inlägg
Gladh skrev:
Få se om jag hänger med här...
Du har en lista med structer som inte kan innehålla en konstruktor, men för att binda listan till en datagridview så måste struterna ha en konstruktor annars fungerar det inte, rätt?
Om det är fallet så hade jag helt enkelt skapat mig en "wrapperklass" som hade motsvarat er struct, omvandlat din lista av structer till en lista av wrapperklasser och bundit dessa till datagridviewn. Det enklast sättet att mappa mellan structen och wrapperklassen blir att wrapperklassen innehåller en struct och alla properties i wrapperklassen pekar ner på samma property i structen.
- M
Prestandan för detta torde bli önskvärd... Ska genast ge mig på det! Tack för tipset!
CatZMedlem sedan jan. 20022 440 inlägg Där var jag katig och markerade tråden som löst för jag trodde att jag bergis kunde hitta någon genomgång på nätet men icke!
Några förslag eller länkar till hur man kan göra / tänka för att det ska bli rätt?
Vi kan ta ett enkelt exempel
[StructLayout(LayoutKind.Sequential)]
public struct SimpleStruct
{
public short ID;
public string Description;
public uint Value;
}
Sedan får jag skapa en klass som representerar SimpleStruct
public class SimpleStructWrapper
{
private short id;
private string description;
private uint value;
public SimpleStructWrapper(short _id, string _description, uint _value)
{
id = _id;
description = _description;
value = _value;
}
}
Hur ska jag tänka nu? Jag behöver ju en extern funktion som tar emot min lista med SimpleStruct och omvandlar den till en lista med SimpleStructValue, vad är mest prestanda effektivt nu? Att loopa igenom hela innehållet i listan?
Jag tror du är ute efter något sådant här.
struct InfoHolderStruct
{
Id,
Name
}
public class InfoHolder
{
private InfoHolderStruct _innerStruct;
public InfoHolder(InfoHolderStruct innerStruct)
{
_innerStruct = innerStruct;
}
public InfoHolder()
{
_innerStruct = new InfoHolderStruct;
public InfoHolderStruct InnerStruct
{
get;
}
public Guid Id
{
get { return _innerStruct.Id; }
set { _innerStruct.Id = value; }
}
public string Name
{
get { return _innerStruct.Name; }
set {_innerStruct.Name = value; }
}
CatZMedlem sedan jan. 20022 440 inlägg Absolut! Det fungerar ju kanon jag lämna gärna synpunkter på följande metod för att konvertera...
private List<StructHolder> GenerateUsableList(List<SimpleStruct> structList)
{
List<StructHolder> usableList = new List<StructHolder>();
structList.ForEach(delegate(SimpleStruct simpleStruct)
{
usableList.Add(new StructHolder(simpleStruct));
});
return usableList;
}
Blir det ok prestandamässigt? I det här läget är iofs inte prestandan av yttersta vikt men det vore ju ändå skönt om det går att lösa såhär smidigt.
CatZMedlem sedan jan. 20022 440 inlägg Ska väl tillägga att jag endast testat lokalt på en simple webform med 100 rader... ska testa att lägga till 100 000 rader...
CatZMedlem sedan jan. 20022 440 inlägg Det var enda in i helvete vad det gick fort... PANG färdigt! Det verkar defintivt vara modellen att köra på!
Tack för hjälpen Gladh och Nickemannen!!!
CatZMedlem sedan jan. 20022 440 inlägg Jag testade att köra 10 000 000 dvs 10 miljoner rader och det tog ca 75 sekunder för min winform att skapa de raderna samt konvertera dem till en användningsbar lista och presentera dem i min datagridview...
SimpleStruct har två "kolumner" id och värde.
CatZMedlem sedan jan. 20022 440 inlägg Låt oss nu spåna att jag endast vill ha en enda metod för att returnera en bindningsbar lista så vill jag kunna göra ungefär följande
// Method to convert a list of structs to a bindable list
private List<HolderType> GenerateUsableList<HolderType>(List<StructType> structlist)
{
// Create the usable list
List<HolderType> holderlist = new List<HolderType>();
// run through the structlist and add every struct to the holderlist
structlist.ForEach(delegate(StructType structtype)
{
holderlist.Add(new HolderType(structtype));
});
return holderlist;
}
Här saknas någonting jag får upp att StructType saknas när jag vill ha den som parameter kan jag inte använda mig av okända StructTyper som parameter?
GladhMedlem sedan maj 20012 812 inlägg
catz skrev:
Jag testade att köra 10 000 000 dvs 10 miljoner rader och det tog ca 75 sekunder för min winform att skapa de raderna samt konvertera dem till en användningsbar lista och presentera dem i min datagridview...
Av de 75 sekunderna så gick säkert 74.5 sekunder till att binda alla dessa poster till din datagridview!!!
Själva konverteringen är blixtsnabb då du aldrig konverterar något, utan helt enkelt skapar ett nytt objekt och lägger in din strukt där. Om du tänker använda dig av riktigt många objekt (nu kanske 10 miljoner är overkill :) ) men iallafall run 100.000 och dessa tar några byte, så kanske det är bättre med klasser istället för strukter, för JAG TROR att du kommer skapa en ny minesarea i din heap för din strukt i klassen medans om du använt en klass istället så hade du bara fått 2 referenes till samma område i stacken.. men det är säkert någon annan som har bättre koll på vad som händer med strukter när man flyttar runt dem till olika objekt...
- M
GladhMedlem sedan maj 20012 812 inlägg
Catz skrev:
Här saknas någonting jag får upp att StructType saknas när jag vill ha den som parameter kan jag inte använda mig av okända StructTyper som parameter?
Du måste skicka med StructType till metoden också annars vet den ju bara av vilken typ din HolderType är.
private List<HolderType> GenerateUsableList<HolderType, StructType>(List<StructType> structlist)
- M
CatZMedlem sedan jan. 20022 440 inlägg
Gladh skrev:
Av de 75 sekunderna så gick säkert 74.5 sekunder till att binda alla dessa poster till din datagridview!!!
Själva konverteringen är blixtsnabb då du aldrig konverterar något, utan helt enkelt skapar ett nytt objekt och lägger in din strukt där. Om du tänker använda dig av riktigt många objekt (nu kanske 10 miljoner är overkill :) ) men iallafall run 100.000 och dessa tar några byte, så kanske det är bättre med klasser istället för strukter, för JAG TROR att du kommer skapa en ny minesarea i din heap för din strukt i klassen medans om du använt en klass istället så hade du bara fått 2 referenes till samma område i stacken.. men det är säkert någon annan som har bättre koll på vad som händer med strukter när man flyttar runt dem till olika objekt...
- M
Ska kolla, det blir inte mer än 600*3*3 structer dock...
Gladh skrev:
Du måste skicka med StructType till metoden också annars vet den ju bara av vilken typ din HolderType är.
Nu är jag lite tillbaka på noll då jag givetvis inte kan göra
holderlist.Add(new StructHolder(structtype));
StructHolder doesnt have the new constraint...
CatZMedlem sedan jan. 20022 440 inlägg Kan jag använda ConstructorInfo till detta?
CatZMedlem sedan jan. 20022 440 inlägg private List<HolderType> GenerateUsableList<HolderType, StructType>(List<StructType> structlist)
where HolderType : new()
{
// Create the usable list
List<HolderType> holderlist = new List<HolderType>();
// run through the structlist and add every struct to the holderlist
structlist.ForEach(delegate(StructType structtype)
{
[b]holderlist.Add(new HolderType(structtype));[/b]
});
return holderlist;
}
Tänkte det skulle fungera men då får jag felmeddelande på raden i fetstil och meddelandet lyder
Visual Studio 2008 skrev:
'HolderType': cannot provide arguments when creating an instance of a variable type
Så jag försökte lägga till
where HolderType: class, new()
men det hjälper inte heller.
Det jag helst skulle vilja göra är
where: class, HolderType, new()
men då får jag ett meddelande om Circular dependancy. Attans att jag ska in och pilla på sådana här fullständigt onödiga saker.
CatZMedlem sedan jan. 20022 440 inlägg Lösningen ser ut som följer
// Method to convert a list of structs to a bindable list
private List<HolderType> GenerateUsableList<HolderType, OriginType>(List<OriginType> originlist)
where HolderType : new()
{
// Create the usable list
List<HolderType> holderlist = new List<HolderType>();
// Convert the structlist and add every struct to the holderlist
structlist.ForEach(delegate(OriginType origintype)
{
holderlist.Add((HolderType)Activator.CreateInstance(typeof(HolderType), origintype));
});
return holderlist;
}
Activator.CreateInstance är inte så snabb så denna lösning bör fungera bättre.
/// Interface för Wrappklassen
public interface IStructHolder<TStruct>
{
TStruct InnerStruct { get; set; }
}
///Skapa metod
public static IList<TClass> GetWrappedList<TClass, TStruct>(IEnumerable<TStruct> structList)
where TClass : IStructHolder<TStruct>, new()
{
IList<TClass> wrappedClassList = new List<TClass>();
foreach (TStruct innerStruct in structList)
{
TClass wrappedStructClass = new TClass();
wrappedStructClass.InnerStruct = innerStruct;
wrappedClassList.Add(wrappedStructClass);
}
return wrappedClassList;
}