[C#]Cross-thread operation not valid
Bonjour,
j'aimerai créer une class possédant des événements. Cette class lance également un thread qui va déclancher l'événement. Dans le code où est instancier un objet de cette class, j'abonne une méthode à l'événement. Dans cette méthode je modifie la propriété text d'un objet RichTextBox. Lorsque l'événement survient la méthode abonnée à l'événement s'éxécute bien mais une exception survient au momment de la modification du RichTextBox. Ceci survient car l'appel de cette méthode provient d'un autre thread que celui où est instancié l'objet RichTextBox. Une solution est d'utiliser la méthode BeginInvoke et de lui passer une méthode delegate.
Cependant existe-t-il une autre solution permettant d'éviter l'utilisation de la méthode BeginInvoke?
En fait j'aimerai que l'utilisateur de la class générant les événements n'ai pas à ce soucier des problèmes de "Cross-thread operation not valid"
Merci pour votre support
Cross-thread operation not valid
La méthode que propose yagosacquet est celle que j'utilise aussi, la méthode de Biloutor ne me plaît pas car il faut prendre en compte la synchronisation entre les le thread générant l'événement et le thread de l'IHM.
Bref, mon problème n'est cependant pas complètement résolu. En fait avec la méthode de yagosacquet ça fonctionne très bien mais l'utilisateur de la classe générant l'événement doit savoir qu'il doit utiliser la méthode Invoke().
Moi j'aimerai faire en sort qu'il n'a pas besoin de savoir tout ça.
Lorsqu'on utilise un composant System::Windows::Forms::Button, il n'est pas nécéssaire d'utiliser la méthode Invoke() dans la methode System::Void buttonXY_Click(System::Object^ sender, System::EventArgs^ e). Comment est solutionné l'appel de cette événnement OnClick dans las classe System::Windows::Forms::Button?
J'aimerai aboutir au même résultat...
Est-ce possible?
Merci
hrp
Cross-thread operation not valid
Merci à shwin,
je vais analyser un peu avec le reflector. Cette outil est géniale! merci beaucoup pour votre aide.
@+
hrp
une solution cross-Threading sans Invoke
Bonjour Gogor,
La méthode de Yagosacquet est celle que l'on retrouve le plus souvent dans les forum et dans les tutoriels. J'ai finalement trouvé une autre méthode tout aussi efficace il me semble et qui pourrait convenir.
On peut trouver cette technique ici: http://msdn2.microsoft.com/fr-fr/lib...67(VS.80).aspx
Une version un peu simplifier de tout ça (en c++/cli):
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
using namespace System::ComponentModel;
using namespace System::Threading;
ref class MaClass
{
public:
MaClass()
{
this->isThreadSafe = false;
//lancement de mon thread
this->monThread= gcnew Thread(gcnew ThreadStart(this, &MaClass::MaThreadProc));
this->monThread->Start();
}
MaClass(Object^ SynchronizingObject)
{
this->asyncOp = AsyncOperationManager::CreateOperation(SynchronizingObject); //initialisation de mon opération asynchrone
this->onInitialized = gcnew SendOrPostCallback(this, &MaClass::ReportInitialized); //initialisation du delegate
this->isThreadSafe = true;
//lancement de mon thread
this->monThread= gcnew Thread(gcnew ThreadStart(this, &MaClass::MaThreadProc));
this->monThread->Start();
}
private:
AsyncOperation^ asyncOp;
Boolean isThreadSafe;
Thread^ monThread;
public:
event EventHandler^ Initialized; //mon event
protected:
SendOrPostCallback^ onInitialized; //mon delegate
protected:
void ReportInitialized(Object^ obj)
{
try
{
this->Initialized(this, EventArgs::Empty);
}
catch(Exception^ ex)
{
ex->Message;
}
}
private:
void MaThreadProc(void)
{
for(int i = 0; i < 10; i++)
{
Thread::Sleep(1000); //j'initialise pendant 10s, c'est long...
}
//génération de mon event
if(this->isThreadSafe)
{
this->asyncOp->Post(this->onInitialized, EventArgs::Empty);
}
else
{
this->ReportInitialized(EventArgs::Empty);
}
}
}; |
pour l'utilisation de cette class il suffit d'instancier un object de cette class et d'abonner une fonction à son event Initialized. Pour être Thread-safe il faut utiliser le constructeur avec parametre et passer this comme ceci:
Code:
1 2 3
|
MaClass^ maClass = gcnew MaClass(this);
maClass->Initialized += gcnew EventHanlder(this, &maClass_Initialized); |
et dans la fonction maClass_Initialized on est thread-safe c'est à dire dans le bon thread
Code:
1 2 3 4 5 6
|
void maClass_Initialized(Object^ sender, EventArgs^ e)
{
//update d'un control...
this->monTextBox->Text = "maClass initialisée!";
} |
au passage, tu trouveras Reflector ici:
http://www.aisto.com/roeder/DotNet/
j'espère ne pas avoir fait trop de faute dans l'exemple ci-dessus...
PS: peut-être qu'il existe encore une autre technique avec l'interface ISynchronizeInvoke. J'ai pas encore eu le temps d'anaylser cette interface mais elle semble être conçue pour ça également. J'ai remarqué que le composant EventLog de System::Diagnostics utilise cette interface.
@++
hrp