c# - Multithreading and updating UI in Tray-only application, -


i have tray-only application gathering data service on separate thread , updating context menu it.

ui can updated on ui thread, i'm trying invoke ui update, without window there no handle created, invoke throw invalidoperationexception, , invokerequired returns false.

so how can update context menu in case?

edit: create tray icon this:

public class trayicon : idisposable {     notifyicon ni;     public trayicon()     {         ni = new notifyicon();     }      public void display()     {         ni.icon = resources.trayicon;         ni.text = "trayapp";         ni.visible = true;         ni.contextmenustrip = new contextmenu();      }      public void dispose()     {         ni.dispose();     } }  public static void main(string[] args)     {         application.enablevisualstyles();         application.setcompatibletextrenderingdefault(false);          using (trayicon icon = new trayicon())         {             settings = new settings();             icon.display();             application.run();         }     } 

edit2: data stored inside obix worker object available staticaly in application, event onupdated handlers execute after each update.

public class contextmenu: contextmenustrip {      private bool _issettingsopen = false;     private deviceslist deviceslist;      public contextmenu()     {         deviceslist = new deviceslist();         deviceslist.text = "devices";         deviceslist.image = resources.online;         items.add(deviceslist);         app.obix.onupdated += invokeupdate;     }      void invokeupdate(object o, eventargs e)     {         console.writeline(this.ishandlecreated);//<<false         contextmenu menu = this;              methodinvoker method = delegate             {                 deviceslist.repopulate();             };             invoke(method);//<<invalidoperationexception     } }  public class deviceslist : toolstripmenuitem  {      public deviceslist()     {         repopulate();     }      public void repopulate()     {         iqueryable<toolstripitem> listed = (iqueryable<toolstripitem>)dropdownitems.asqueryable();         ienumerable<toolstripitem> remove = listed.where(item => !app.obix.devices.contains(new devicestatus(item.name)));         foreach (toolstripitem ritem in remove)         {             dropdownitems.remove(ritem);         }         ienumerable<devicestatus> add = app.obix.devices.where(device => dropdownitems.indexofkey(device.name) == -1);         foreach (devicestatus adevice in add)         {             toolstripmenuitem item = new toolstripmenuitem();             item.name = adevice.name;             item.text = adevice.name;             dropdownitems.add(item);         }         foreach (toolstripmenuitem item in dropdownitems)         {             devicestatus device = app.obix.devices.single(_device => _device.name == item.name);             if (device.state == "down")                 item.image = resources.offline;             else                 item.image = resources.online;         }      } }  } 

you can check invokerequired , invoke using contextmenustrip. it's control.

example

using system; using system.windows.forms; static class program {     [stathread]     static void main()     {         application.enablevisualstyles();         application.setcompatibletextrenderingdefault(false);         var notifyicon1 = new notifyicon();         notifyicon1.icon = new form().icon;         notifyicon1.visible = true;         var contextmenustrip1 = new contextmenustrip();         notifyicon1.contextmenustrip = contextmenustrip1;         var timer = new system.timers.timer();         timer.interval = 3000;         timer.elapsed += (sender, e) =>  /*runs in different thread ui thread.*/         {             if (contextmenustrip1.invokerequired)                 contextmenustrip1.invoke(new action(() =>                 {                     contextmenustrip1.items.add(e.signaltime.tostring());                 }));             else                 contextmenustrip1.items.add(e.signaltime.tostring());         };         timer.start();         application.run();     } } 

note 1: invokerequired property , and invoke method belong control class. in above code, before showing contextmenustrip invokerequired returns false, because handle has not been created. show contextmenustrip, invokerequired return true.

note 2: invokerequired , invoke use deepest parent available. in case control does't have parent, control used.


Comments

Popular posts from this blog

python - Operations inside variables -

Generic Map Parameter java -

arrays - What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it? -