View Full Version : [C#] Control.BeginInvoke
zakmckraken
06-07-2011, 14:37
Ciao a tutti!
Piccolo problema con un "vago" aroma di .NET in salsa win32..
Mi trovo a dover far comunicare degli UserControl custom all'interno di una applicazione WinForm in C#, abituato a MFC e Win32 (e altri 12000 sistemi pressoche'identici con le loro simpatiche code), mi aspettavo di registrare un messaggio custom e di poter mandare questo messaggio con la solita vecchia PostMessage a tutti i controlli presenti nell'applicativo....ma sembra che la cosa non sia cosi'banale :(
Raspando su google & co mi sono imbattuto nel meraviglioso mondo della BeginInvoke...e li ho perso il filo: e possibile che uno debba sapere a priori qual'e'il controllo che ricevera'il messaggio? Non e'piu'possibile far partire un messaggio e lasciare che solo gli interessati lo considerinto? Sembra quasi che per amore di OO (object orientation) non sia piu'possibile???
Grazie a chiunque risponda!
Zak
BeginInvoke non centra con il riuscire a fare in modo che solo qualcuno tra una collezione di controlli riceva un determinato messaggio.
Magari lo dovrai anche usare, ma non per quel motivo.
Usando uno UnityInjection con magari anche un EventBus, il tuo problema diventerebbe banale.
Alternativamente eleggi un oggetto ad essere possessore di un evento.
Ad esempio la form/window che contiene tutto.
Dota la classe anche di un metodo per invocare l'evento.
public event Action<string> Gotcha.
public void GotchaFire(string str)
{
if (Gotcha!=null)
Gotcha(str);
}
All'interno di ciascun controllo di quelli interessati vai a cercare la finestra
(questo andare a cercare e' proprio uno delle cose che la unity injection e l'EventBus ti permetterebbero di evitare)
E sottoscriviti all'evento, facendogli fare qualcosa.
var formContainer = qualcosa;
formContainer.Gotcha += (str) =>
{
if (str=="EDirettoAMe")
FaccioQualcosa();
}
Da dove dovrai segnalare, semplicemente chiama il metodo della finestra.
var formContainer = qualcosa;
formContainer.GotchaFire("messaggioDaMandare");
per evitare problemi di sottoscrizioni non rilasciate, aggiungi alla chiusura della form (evento Closed) il codice relativo a cancellare TUTTE le sottoscrizioni fatte da qualunque controllo.
Gotcha = null;
zakmckraken
07-07-2011, 15:41
Ciao! (& grazie per la risposta!)
Infatti mi manca una sano bus/coda dove far girare i messaggi...
Attualmente ho risolto utilizzando una classe di supporto...che fa praticamente da bus :) insomma mi sono riciclato la struttura delle applicazioni MFC con la dichiarazione degli handler.
Ho adesso un singleton (la classe di supporto) su cui i vari UserControls si registrano con il loro bel delegate da eseguire stile
HelperClass.RegisterMessage("sonoUnMessaggio",this.OnSonoUnMessaggio);
(con la unregister nei "distruttori" delle classi che si registrano)
E a questo punto per invocare il tutto faccio qualcosa del genere
HelperClass.PostMessage("sonoUnMessaggio",parametriVari);
A questo punto dentro l'helper class andro'finalmente a scorrermi tutti gli "handler" per il messaggio con la BeginInvoke (notare che sono sulla GUI e non sto lavorando sulla Delegate.BeginInvoke ma sulla Control)
((Control)actions[i].Target).BeginInvoke(
new SynchroAdapterDelegate(actions[i]),
paramsToPass);
Dove actions e'la lista dei delegates associati all'azione, mentre Target e'l'oggetto di cui la delegate verra'invocata
Zak
PS rivoglio i messaggi disaccoppiati uffaaaaaaa :mc:
Ciao! (& grazie per la risposta!)
Infatti mi manca una sano bus/coda dove far girare i messaggi...
Attualmente ho risolto utilizzando una classe di supporto...che fa praticamente da bus :) insomma mi sono riciclato la struttura delle applicazioni MFC con la dichiarazione degli handler.
Ho adesso un singleton (la classe di supporto) su cui i vari UserControls si registrano con il loro bel delegate da eseguire stile
HelperClass.RegisterMessage("sonoUnMessaggio",this.OnSonoUnMessaggio);
(con la unregister nei "distruttori" delle classi che si registrano)
E a questo punto per invocare il tutto faccio qualcosa del genere
HelperClass.PostMessage("sonoUnMessaggio",parametriVari);
A questo punto dentro l'helper class andro'finalmente a scorrermi tutti gli "handler" per il messaggio con la BeginInvoke (notare che sono sulla GUI e non sto lavorando sulla Delegate.BeginInvoke ma sulla Control)
((Control)actions[i].Target).BeginInvoke(
new SynchroAdapterDelegate(actions[i]),
paramsToPass);
Dove actions e'la lista dei delegates associati all'azione, mentre Target e'l'oggetto di cui la delegate verra'invocata
Zak
PS rivoglio i messaggi disaccoppiati uffaaaaaaa :mc:
Per disaccoppiare si usano normalmente i generics, cosi' da riferirsi direttamente ad un tipo di messaggio.
Ogni tipo di evento e' una classe a se' stante, e il codice usante compiera' cose del genere:
Bus.RaiseEvent<ColoraDiRosso>();
Bus.RaiseEvent<SalveLePreferenze>();
E il codice intercettante qualcosa come
Bus.Subscribe<ColoraDiRosso>( MetodoCheVaAColorareDiRosso);
Bus.Subscribe<SalveLePreference>( MetodoCheSalveLePreference );
Cerca in giro, se non addirittura usa direttamente, EventBus
Comunque il problema della BeginInvoke non centra nulla con questo pattern.
La BeginInvoke e' semplicemente necessaria, sotto Winform, quando occorre agire su una finestra/controllo della GUI a partire da Thread che non sono il Thread della finestra.
E ci sono anche metodi per evitarlo ed avere quindi codice piu' pulito.
Cerca in giro MVP o MVVM.
Kralizek
08-07-2011, 10:36
mai usato MVVM in contesto winforms, é supportato bene?
mai usato MVVM in contesto winforms, é supportato bene?
MVVM sotto WPF
Sotto Winform MVP o MVC
devbeginner
11-07-2011, 10:34
Ho adesso un singleton (la classe di supporto)
Singleton :stordita:
MVVM sotto WPF
Sotto Winform MVP o MVC
MVVM con WPF ed il sottoinsieme Silverlight :)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.