Avatar billede dasch87 Nybegynder
02. februar 2011 - 19:18 Der er 10 kommentarer

WPF Datagridview mangler refresh når jeg tilføjer til binding collection

Hej Eksperter

Jeg har et problem med at mit datagridview ikke opdateres løbende som jeg indsætter flere objekter i min binding collection. Jeg her en knap jeg trykker på og indsætter så et antal objekter i min binding collection. Dette vil jeg gerne gøre med et interval på 1 sec. Min kode er følgende:

ObservableCollection<OrderDetail> bindingList = new ObservableCollection<OrderDetail>();

dataGrid.ItemSource = bindingList;
private void btnSimulate_Click(object sender, RoutedEventArgs e)
{

for (int i = 0; i < 30; i++)
{
    bindingList.Add(new OrderDetail(...));
    Thread.Sleep(1000);
}
}

Først når alle objekter er indsat og metoden er kørt færdig bliver datagridview'et opdateret. Jeg skal kunne se elementerne tilføjet hvert sekund. Jeg har prøvet dataGrid.Items.Refresh()... Og det virker ikke.

På forhånd mange tak.

/Dasch
Avatar billede tjens Nybegynder
02. februar 2011 - 20:21 #1
Din kode kører i den tråd, der også opdaterer skærmen.
Den opdaterer ikke brugerfladen, så længe din applikations kode kører.

Send din dataopdatering ud i en ny tråd.

(hvilket man altid bør gøre, hvis koden tager mere end et splitsekund)
Avatar billede dasch87 Nybegynder
02. februar 2011 - 20:27 #2
Tak for dit svar tjens, men kan du prøve at forklare det nærmere, jeg mener nemlig at jeg har forsøgt det du beskriver. På følgende måde:

private void btnSimulate_Click(object sender, RoutedEventArgs e)
{
    Thread thread = new Thread(new ThreadStart(foo));
    thread.Start();
}

private void foo()
{
    IList<OrderDetail> ods =
        orderDetails.Take(3).ToList<OrderDetail>();

    bindingList.Add(ods[0]);
}

Men dette giver mig følgende exception:

NotSupportedException:
This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.
Avatar billede tjens Nybegynder
02. februar 2011 - 20:37 #3
Jeg er desværre kun igang med at lære det, så jeg kan nok ikke hjælpe med testede eksempler.

Men denne artikel forklarer det:
http://msdn.microsoft.com/en-us/magazine/cc163328.aspx
Måske er det timeren sidst i artiklen du har brug for.
Avatar billede johny Nybegynder
02. februar 2011 - 23:02 #4
Prøv med:

private void foo()
{
this.Dispatcher.Invoke(() => {
IList<OrderDetail> ods =
        orderDetails.Take(3).ToList<OrderDetail>();

    bindingList.Add(ods[0]);
}
}
Avatar billede platik Nybegynder
03. februar 2011 - 12:21 #5
Vil jo mene du skal invoke før det virker når du arbejder med tråde på din GUI. Din maintråd "ejer" jo dit datagrid. Så hvis du invoker dit refresh burde det virke.

Prøv:
private void btnSimulate_Click(object sender, RoutedEventArgs e)
{
    Thread thread = new Thread(new ThreadStart(foo));
    thread.Start();
}

private void foo()
{

for (int i = 0; i < 30; i++)
{
    bindingList.Add(new OrderDetail(...));
    dataGrid.Dispatcher.Invoke((Action)delegate { dataGrid.Items.Refresh(); });
    Thread.Sleep(1000);
}
}
Avatar billede tjens Nybegynder
04. februar 2011 - 18:43 #6
Jeg har nu lavet løsning med Backgroundworker og ReportProgress.

ReportProgress bruges i de fleste tutorials på nettet kun til at afgive en procent i felt ProgressChangedEventArgs.ProgressPercentage, men jeg debuggede lidt for at finde ud af hvad det andet felt  ProgressChangedEventArgs.UserState kunne bruges til.

Det viste sig at UserState er ret generisk, og vi kan derfor sende hele nye objekter fra background-tråden til UI-tråden.
Derved kan UI-tråden løbende modtage nye objekter, som kan tilføjes til den observableCollection som opdaterer skærmen.

Demo XAML: http://pastebin.com/Qry6gvYz
Demo C#  : http://pastebin.com/uGMkAuHN
Avatar billede dasch87 Nybegynder
04. februar 2011 - 19:02 #7
Mange tak for alle jeres forslag. Det var helt korrekt med at jeg skulle bruge dispatch'eren og oprette en tråd som tjens kom med forslag til fra start af. Jeg fik det meget til at virke ligesom platik har foreslået. Lidt det samme som Johny var inde på.

Platik og Johny, hvis i smider et svar får i også lidt af pointene, men hoveddelen af point'ene går til tjens.

Mange tak for jeres hjælp allesammen.

Følgende virkede for mig:

private void btnSimulate_Click(object sender, RoutedEventArgs e)
{
    Thread thread = new Thread(new ThreadStart(foo));
    thread.Start();
}

private void foo()
{

for (int i = 0; i < 30; i++)
{
    bindingList.Add(new OrderDetail(...));
Application.Current.Dispatcher.Invoke(
                DispatcherPriority.Send,
                new Action(() => dataGrid.Items.Refresh());
    Thread.Sleep(1000);
}
}

/Dasch
Avatar billede johny Nybegynder
05. februar 2011 - 10:53 #8
Nah den tager de andre bare. Glad for at du fandt en løsning. :)
Avatar billede dasch87 Nybegynder
05. februar 2011 - 15:52 #9
@Johny, det var alt sammen takket være jeres hjælp;)
Avatar billede platik Nybegynder
06. februar 2011 - 13:35 #10
Velbekomme :-).
Avatar billede Ny bruger Nybegynder

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.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester