Hej! Som du vet och har märkt så kan man få ganska märkliga resultat om Hej och tack för ditt svar! du gör inte datakällan på något vis medveten om uiet, du gör din datavy medveten om att den kan bli uppdaterad från flera olika trådar. databindning och trådar
Om man uppdaterar UI't från en annan tråd än den tråd som skapade UI't så kan det uppstå rätt så konstiga fenomen. För att
lösa detta kan man kolla MyControl.InvokeRequired och i så fall köra MyControl.Invoke...
Vid databindning så måste man tydligen oxå göra det. Jag labbade med att manuellt uppdatera en Datatable som en DataGrid
var bunden till och programmet hängde sig. Men om jag körde Invoke innan jag uppdaterade datakällan så fungerade det fint.
Visst, det funkar precis som om man skulle skrivit direkt till kontrollen. Men vad händer om man inte har tillgång till
UI't när man uppdaterar DataTablen? Detta kanske görs i en dll långt bort som inte har en aning om hur datat visas. Hur
löser man det??
Tack på förhand
Peter BladhSv: databindning och trådar
man uppdaterar UIet från en annan kontroll än den som ursprungligen
skapade fönstret. (Detta eftersom MS bla lagrar lite information i TLS
på den skapande tråden)
Så nu till din fråga, hur undviker man problem med databindning och
trådar? Databindningen utgår från event från din datatabell och eftersom
dessa event kommer att exekveras av den tråd som uppdaterade tabellen
så kommer datagriden att försöka uppdatera sig på fel tråd.
Vad kan man då göra åt det?
Till att börja med måste vi förstå hur bindningen egentligen går till.
DataGrid binder till allt som implementerar IList eller IListSource.
(DataTable implementerar IListSource, eftersom tabellen i sig
aldrig implementerar IList för det gör DataView klassen)
Om vi istället för att binda mot DataTable klassen binder
mot DataView så har vi en möjlig ingång till att förändra
beteendet i vårt trådade specialfall.
Börja med att skapa en ny DataView class genom arv.
Skapa en ny OnListChanged genom override.
Låt denna kontrollera om vi är på rätt tråd annars
växla till den riktiga tråden.
Källkoden nedan är inte helt komplett men den fungerar
och går lätt att bygga vidare.
/// <summary>
/// Special dataview class that invokes the event on the
/// correct thread for this control
/// </summary>
public class ThreadAwareDataView : DataView
{
Control _invokeTarget;
public ThreadAwareDataView( Control controlToInvoke )
{
_invokeTarget = controlToInvoke;
}
public ThreadAwareDataView( Control controlToInvoke, DataTable table )
: base( table )
{
_invokeTarget = controlToInvoke;
}
// more ctors needed to be complete ...
protected override void OnListChanged(System.ComponentModel.ListChangedEventArgs e)
{
if( _invokeTarget != null )
{
// force this call over to the correct thread if needed
if( _invokeTarget.InvokeRequired )
{// wrong thread, force over to correct thread
_invokeTarget.Invoke( new OnListChangedCallback( OnListChanged ), new object[]{ e } );
}
else
{
base.OnListChanged (e);
}
}
else
{
base.OnListChanged( e );
}
}
private delegate void OnListChangedCallback( System.ComponentModel.ListChangedEventArgs e );
}Sv: databindning och trådar
Jag tycker dock att det är konstigt att man måste lösa det genom att göra datakällan medveten UI't.
/peterSv: databindning och trådar
Alternativet är att skriva en ny CurrencyManger som hanterar trådproblemet, eller tom en ny DataGrid.
Dock är datavy modellen enklast att implementera.