Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
SortableBindingList + Virutal Mode im DGV + Sotierprobleme
Siedlerchr
myCSharp.de - Member



Dabei seit:
Beiträge: 178
Herkunft: NRW

Themenstarter:

SortableBindingList + Virutal Mode im DGV + Sotierprobleme

beantworten | zitieren | melden

Hallo zusammen,

ich habe ne SortableBindingList an ein DGV gehängt. Das funktioniert auch soweit alles.
Das DGV ist im Virtual Mode und da kriege ich beim sortieren - teilweise- Fehlermeldungen:
Fehler
---------------------------
Standard-Fehlerdialogfeld für DataGridView
---------------------------
DataGridView-Ausnahme:
System.IndexOutOfRangeException: Der Index 6 hat keinen Wert.

bei System.Windows.Forms.CurrencyManager.get_Item(Int32 index)

bei System.Windows.Forms.DataGridView.DataGridViewDataConnection.GetError(Int32 boundColumnIndex, Int32 columnIndex, Int32 rowIndex

Behandeln Sie das DataError-Ereignis, um dieses Standarddialogfeld zu ersetzen.


Das eiinzige was mir zu diesem Fehler einfällt, ist das das für jedes Element im DGV/Liste kommt, der IndexWert entspricht der Row.

Was vielleicht noch interessant ist: Die Liste die als DataSource am DGV hängt wird von einem Thread in 1000 Schritten befüllt und nach jedem Schritt wird die DataSource wieder auf die Liste gesetzt.

Hier noch mein CellValueNeeded Event:

private void dgvDeleteRuns_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
        {
            e.Value = allRuns[e.RowIndex];
        }




Wenn ich die Liste z.B: per Where einschränke und das Ergebnis als neue Liste ans DGV hänge (auch eine SortableBindingList), dann funktioniert das Sortieren einwandfrei....


Ich habe auch schon probiert. die LIste ans DGV als DataSource zu setzen, wenn alle Daten geladen sind. Aber da geht das sortieren ebenfalls nicht.

Hat jemand ne Idee warum das nur bei alllen nicht geht? Ich hab mit dem VirtaulMode noch nicht so viel Erfahrung gesammelt.
Attachments
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10.006

beantworten | zitieren | melden

Wenn du den IndexOutOfRangeException bekommst ist die Liste anscheinend noch nicht bis dahin gefüllt.
Setzt du evtl RowCount bevor du die Daten gelesen hast?
Zitat
Die Liste die als DataSource am DGV hängt wird von einem Thread in 1000 Schritten befüllt und nach jedem Schritt wird die DataSource wieder auf die Liste gesetzt.
Was denn nun, Virtual mode oder DataSource, beides macht keinen sinn.
private Nachricht | Beiträge des Benutzers
Siedlerchr
myCSharp.de - Member



Dabei seit:
Beiträge: 178
Herkunft: NRW

Themenstarter:

beantworten | zitieren | melden

Zitat von FZelle
Was denn nun, Virtual mode oder DataSource, beides macht keinen sinn.

o.O - Hm, dann muss ich mich doch nochmal genauer einlesen. Ich hatte das bisher so verstanden, dass das Virtual Mode nur dann funktioniert, wenn ich auch ne DataSource habe und meine Items DataBound sind
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo Siedlerchr,
Zitat
Die Liste die als DataSource am DGV hängt wird von einem Thread in 1000 Schritten befüllt
das ist nicht erlaubt und kann zu abstrusen Fehlern führen, siehe [FAQ] Controls von Thread aktualisieren lassen (Control.Invoke/Dispatcher.Invoke).

herbivore
private Nachricht | Beiträge des Benutzers
Siedlerchr
myCSharp.de - Member



Dabei seit:
Beiträge: 178
Herkunft: NRW

Themenstarter:

beantworten | zitieren | melden

Genau das war mein Problem. Habe das Problem jetzt gelöst, in dem ich die Daten vorher nochmal in eine neue Liste übertrag und diese dann komplett ans DGV hänge.
So klappt es. Ist zwar performancemäßig nicht so toll, aber erstmal ein Anfang

Gruß
Siedlerchr
private Nachricht | Beiträge des Benutzers
yngwie
myCSharp.de - Member



Dabei seit:
Beiträge: 238

beantworten | zitieren | melden

Hallo Siedlerchr,
Zitat von herbivore
Zitat
Die Liste die als DataSource am DGV hängt wird von einem Thread in 1000 Schritten befüllt
das ist nicht erlaubt und kann zu abstrusen Fehlern führen...

Das mit "nicht erlaubt" finde ich etwas zu scharf formuliert... Sagen wir es mal so, wenn deine (Sortable)BindingList Implementierung sich intern mit dem UI-Thread synchronisiert, dann würde herbivore es erlauben, oder?

Siedlerchr, was ich irgendwie nicht ganz verstehe ist die Kombination aus VirtualMode und einer DataSource... Macht so etwas Sinn, bzw schliesst es sich nicht gegenseitig aus? Kannst du eventuell mal einen Link posten wo man über diese Art der Datenbindung nachlesen kann?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von yngwie am .
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo yngwie,

falls eine andere Synchronisation mit dem GUI-Thread möglich wäre, wäre das ausreichend, aber sie ist nicht möglich. Deshalb ist es zwingend, die Änderung von gebundenen Daten im GUI-Thread durchzuführen. Ich bleibe also dabei. Es ist nicht erlaubt, die gebundenen Daten in einem anderen Thread zu ändern.

herbivore.
private Nachricht | Beiträge des Benutzers
yngwie
myCSharp.de - Member



Dabei seit:
Beiträge: 238

beantworten | zitieren | melden

Hallo herbivore,
Zitat von herbivore
...falls eine andere Synchronisation mit dem GUI-Thread möglich wäre, wäre das ausreichend, aber sie ist nicht möglich...

Wieso ist sie denn so kategorisch nicht möglich? Ich habe eine BindingList implementiert die neben Suchen und Sortieren sich bei Bedarf auch noch mit dem UI-Thread synchronisiert. Diese verwende ich fürs Databinding, sogar im Produktivumfeld... funktioniert sehr gut.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von yngwie am .
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo yngwie,

ok, wenn du eine eigene thread-safe BindingList verwendest und auch alle direkt und indirekt in dieser BindingList enthaltenen Objekte, deren Properties, Methoden, Events usw. von sich heraus thread-safe sind, würde es vielleicht gehen. Wobei ich es für wirklich schwierig halte, dies alles (und insbesondere den Enumerator) wasserdicht hinzubekommen und bei Änderungen und Erweiterungen wasserdicht zu halten. [EDIT]Selbst wenn man die Synchronisation der Daten perfekt hinbekommt, ist damit immer noch nicht verhindert, dass gleichzeitige Zugriffe auf das Control selber erfolgen und dieses dadurch inkonsistent wird.[/EDIT]

Was dagegen nicht reicht - und davon war ich ausgegangen -, ist alle Zugriffe auf die Daten aus dem Worker-Thread zu locken. Das reicht nicht, weil das Control von sich aus kein lock beim Zugriff auf die Daten benutzt. Und wenn nur einer von zwei Threads das lock benutzt und der andere nicht, hat man überhaupt nichts gewonnen.

Es mag sein, dass ich meine Aussage in der Absolutheit nicht aufrecht erhalten kann (zumindest wenn du wirklich aufzeigen kannst, wie man den Enumerator thread-safe hinbekommt), aber ich denke, dass deiner Alternative in der Praxis keine größere Bedeutung zu kommt. Vereinfacht würde ich daher immer noch, bei "das ist nicht erlaubt" bleibend, wohl wissend, dass es so gut wie keine Regel ohne Ausnahme gibt. [EDIT]Ich halte die Aussage in ihrer Absolutheit aufrecht[/EDIT]

herbivore
private Nachricht | Beiträge des Benutzers
yngwie
myCSharp.de - Member



Dabei seit:
Beiträge: 238

beantworten | zitieren | melden

Hallo herbivore,
Zitat von herbivore
... ok, wenn du eine eigene thread-safe BindingList verwendest und auch alle direkt und indirekt in dieser BindingList enthaltenen Objekte, deren Properties, Methoden, Events usw. von sich heraus thread-safe sind, würde es vielleicht gehen...

ach nein, so aufwändig muss man es wirlich nicht machen. Zum "aufzeigen" bin ich zu faul, ich sage nur dass der Enumerator in einem typischen Databinding-Scenario keine Rolle spielt. Du kannst mal nach "AsyncBindingList" googlen und dich von der Demoapp überzeugen lassen ;) Und was die Bedeutung für die Praxis angeht... nun nicht selten steht man vor der Aufgabe ein sogenanntes "responsive UI" zu realisieren. Mit einer angepassten BindingList kann man diese Arbeit schneller erledigen und dabei das Komfort von Databinding geniessen. Finde ich äußerst praxisrelevant ;)


Gruß
private Nachricht | Beiträge des Benutzers
herbivore
myCSharp.de - Experte

Avatar #avatar-2627.gif


Dabei seit:
Beiträge: 49.486
Herkunft: Berlin

beantworten | zitieren | melden

Hallo yngwie,

der Beitrag Updating DataBound Controls asynchronously: AsyncBindingList<T> von Daniel Herling bestätigt in jeder Hinsicht meine Meinung:
Zitat von Daniel Herling
However, Windows Forms controls can only be updated on the UI thread. So, if SQL Server changes the string on a different thread than the UI thread updating the applications title on the same thread would be a problem. Luckily, Windows Forms controls have two methods which can be called from any thread in order to update the controls: BeginInvoke and Invoke.

Der Trick der AsyncBindingList ist nun, dass sie sich von selbst darum kümmert, dass das passiert. Es ist also keineswegs so, dass die Datenänderung im Worker-Thread erfolgt, sondern sie wird, wie ich das von Anfang an empfohlen bzw. gefordert habe, an den GUI-Thread delegiert. Ob das Delegieren nun explizit durch den Code des Worker-Thread erfolgt oder implizit durch die AsyncBindingList ändert nichts daran, dass es passieren muss.
Zitat von Daniel Herling
The philosophy behind the AsyncBindingList<T> is to get the updates from the background thread and forward them to the UI thread using WindowsFormsSynchronizationContext.

Dass WindowsFormsSynchronizationContext benutzt wird, tut nichts zu Sache, denn intern benutzt WindowsFormsSynchronizationContext einfach Control.Invoke bzw. Control.BeginInvoke.
Zitat von herbivore
ok, wenn du eine eigene thread-safe BindingList verwendest und auch alle direkt und indirekt in dieser BindingList enthaltenen Objekte, deren Properties, Methoden, Events usw. von sich heraus thread-safe sind, würde es vielleicht gehen
Diese Aussage ziehe ich - nachdem ich nochmal darüber nachgedacht habe - auch wieder zurück. Damit würde man es vielleicht schaffen, dass die Daten selbst konsistent bleiben, aber damit verhindert man nicht, dass direkte Zugriffe auf das Control aus dem Worker-Thread erfolgen, was eben nicht erlaubt ist. Mindestens das Control selbst könnte somit selbst trotz perfekter Synchronisierung der Daten immer noch inkonsistent werden.

Ich komme also wieder zu meiner absoluten Haltung zurück: Zugriffe auf gebundene Daten sind aus dem Worker-Thread nicht erlaubt. Punkt! Sie müssen aus dem GUI-Thread erfolgen.

Dass einem die AsyncBindingList<T> diese Aufgabe abnehmen kann, ist sicher praktisch. Aber ich habe nur gesagt, dass diese Aufgabe ausgeführt werden muss. Darüber, wie man die Aufgabe am besten durchführt, also explizit oder per AsyncBindingList<T>, habe ich keine Aussage getroffen.

herbivore
private Nachricht | Beiträge des Benutzers