c# - ContexMenuStrip oddly-specific weird behaviour -
i testing weird bug encountered in app, , able create simple reproduction:
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(); toolstripmenuitem menu1 = new toolstripmenuitem(); menu1.text = "test"; contextmenustrip1.items.add(menu1); contextmenustrip1.items.add("t1"); contextmenustrip1.items.add("t2"); 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(() => { menu1.dropdownitems.add(e.signaltime.tostring() + "extra"); menu1.dropdownitems.add(e.signaltime.tostring()); })); else { menu1.dropdownitems.add(e.signaltime.tostring() + "extra"); menu1.dropdownitems.add(e.signaltime.tostring()); } }; timer.start(); application.run(); } } note context menu not open, doing of following allows open:
- removing "extra" dropdown items added per execution. (to precise adding 0 or 1 per execution works)
- removing part of code on
invokerequired == false(this allows add multiple items per execution) - removing
t1,t2elements. (it still works without additional items in root)
is bug or doing wrong?
edit: additional found condition (thanks @derape):
- it works if move else branch separate method, not if use same method in invokerequired branch. using 2 method different name , same code works.
possible workaround wearing tigers skin while dancing during full-moon.
if @ invokerequired see there explicit check ishandlecreated returns false. returned value doesn't means don't have invoke, means can not invoke.
to confuse more: must invoke, can't yet.
you can either decide don't if handle not created yet (and miss items) or organize separate queue store items until handle available, similar to:
var items = new list<string>(); timer.elapsed += (sender, e) => { if (contextmenustrip1.ishandlecreated) // invoke, check handle contextmenustrip1.invoke(new action(() => { menu1.dropdownitems.add(e.signaltime.tostring() + "extra"); menu1.dropdownitems.add(e.signaltime.tostring()); contextmenustrip1.refresh(); })); else { lock (items) { items.add(e.signaltime.tostring() + "extra"); items.add(e.signaltime.tostring()); } } }; contextmenustrip1.handlecreated += (s, e) => { lock (items) { foreach (var item in items) menu1.dropdownitems.add(item); contextmenustrip1.refresh(); } items = null; }; another note: need call refresh if items added sub-menu, while menu opened, submenu not yet, odd thing of winforms.
Comments
Post a Comment