Ik ben helemaal nieuw met betrekking tot threading en ben begonnen met het schrijven van een simpel C#.net applicatie in windows. Gewone invokes gaan prima maar nu wil ik vanuit Thread A, welke ik net gemaakt heb, een object in de UI Thread updaten.
Tijdens het starten van de applicatie maak ik dus 2 nieuwe threads, één thread waar de UI in draait en één thread waar van ik de UI moet kunnen updaten. (ThreadTest is de naam van de UI class)
Ik geef de UI class dus door aan de status class. De status class checkt of een bepaalde server online is en van uit daar moet de tray icon in de UI thread worden geupdate.
Om het invoken wat makkelijker te maken gebruik ik deze helper class die alle invokes zou moeten afhandelen
In de UI class zit ook de functie die wordt aangeroepen door de invoke:
In de status class, check function wordt deze code gedraait, die de UIthread dus zou moeten updaten (als ik status niet in een eigen thread uitvoer gaat het goed en zijn er geen invoke problemen).
Connector, Address en UIThread worden in status() vast gesteld. UIThread is de UI class.
De invoke werkt alleen niet op deze manier. Ik heb al wat ge-googled maar heb geen oplossing kunnen vinden voor mijn probleem. Ik heb wel gedacht aan MarsheledInvoke, alleen dit is een private function die ik niet kan aan roepen.
Tijdens het starten van de applicatie maak ik dus 2 nieuwe threads, één thread waar de UI in draait en één thread waar van ik de UI moet kunnen updaten. (ThreadTest is de naam van de UI class)
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| // main Threads ThreadTest UIproc = new ThreadTest(); status CKproc = new status("localhost",UIproc); UIproc.args = args; Thread UI = new Thread(new ThreadStart(UIproc.UIProc)); UI.Name = "User Interface Thread"; UI.ApartmentState = ApartmentState.STA; Thread CK = new Thread(new ThreadStart(CKproc.check)); CK.Name = "Server status Thread"; CK.ApartmentState = ApartmentState.STA; // starting threads UI.Start(); CK.Start(); |
Ik geef de UI class dus door aan de status class. De status class checkt of een bepaalde server online is en van uit daar moet de tray icon in de UI thread worden geupdate.
Om het invoken wat makkelijker te maken gebruik ik deze helper class die alle invokes zou moeten afhandelen
C#:
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
| using System; using System.Collections; using System.Reflection; using System.Reflection.Emit; namespace ThreadingTest { public class SafeInvokeHelper { static readonly ModuleBuilder builder; static readonly AssemblyBuilder myAsmBuilder; static readonly Hashtable methodLookup; static SafeInvokeHelper() { AssemblyName name = new AssemblyName(); name.Name = "temp"; myAsmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.Run); builder = myAsmBuilder.DefineDynamicModule("TempModule"); methodLookup = new Hashtable(); } public static object Invoke(System.Windows.Forms.Control obj, string methodName, params object[] paramValues) { Delegate del = null; string key = obj.GetType().Name + "." + methodName; Type tp; if (methodLookup.Contains(key)) tp = (Type)methodLookup[key]; else { Type[] paramList = new Type[obj.GetType().GetMethod(methodName).GetParameters().Length]; int n = 0; foreach (ParameterInfo pi in obj.GetType().GetMethod(methodName).GetParameters()) paramList[n++] = pi.ParameterType; TypeBuilder typeB = builder.DefineType("Del_" + obj.GetType().Name + "_" + methodName, TypeAttributes.Class | TypeAttributes.AutoLayout | TypeAttributes.Public | TypeAttributes.Sealed, typeof(MulticastDelegate), PackingSize.Unspecified); ConstructorBuilder conB = typeB.DefineConstructor(MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, CallingConventions.Standard, new Type[] { typeof(object), typeof(IntPtr) }); conB.SetImplementationFlags(MethodImplAttributes.Runtime); MethodBuilder mb = typeB.DefineMethod( "Invoke", MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig, obj.GetType().GetMethod(methodName).ReturnType, paramList ); mb.SetImplementationFlags( MethodImplAttributes.Runtime ); tp = typeB.CreateType(); methodLookup.Add(key, tp); } del = MulticastDelegate.CreateDelegate(tp, obj, methodName); return obj.Invoke(del, paramValues); } } } |
In de UI class zit ook de functie die wordt aangeroepen door de invoke:
C#:
1
2
3
4
5
6
7
8
9
| #region Thread Safe interactions public void TrayStatus(bool active) { this.notifyIcon1.Visible = active; this.notifyIcon2.Visible = active ? false : true; } #endregion |
In de status class, check function wordt deze code gedraait, die de UIthread dus zou moeten updaten (als ik status niet in een eigen thread uitvoer gaat het goed en zijn er geen invoke problemen).
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| while(true) { try { this.Connector.Connect(this.Address, 80); SafeInvokeHelper.Invoke(this.UIThread, "TrayStatus", true); System.Windows.Forms.MessageBox.Show("online ("+Address+")"); this.Connector.Close(); } catch { SafeInvokeHelper.Invoke(this.UIThread, "TrayStatus", false); System.Windows.Forms.MessageBox.Show("offline"); } Thread.Sleep(this.TimeOut * 1000); } |
Connector, Address en UIThread worden in status() vast gesteld. UIThread is de UI class.
De invoke werkt alleen niet op deze manier. Ik heb al wat ge-googled maar heb geen oplossing kunnen vinden voor mijn probleem. Ik heb wel gedacht aan MarsheledInvoke, alleen dit is een private function die ik niet kan aan roepen.
[ Voor 9% gewijzigd door codeneos op 25-05-2006 11:07 ]
http://www.tweakers.net/gallery/119170/sys