c# - WPF Dynamic TabControl SelectionChanged bug? -
i creating simple application using c# , wpf using mvvm pattern. there main window few buttons , contentcontrol containing list of view models, 1 of them being searchviewmodel. buttons flip between view models.
the searchviewmodel bound searchview , contains tabcontrol. itemssource property bound list of searchtabviewmodels. in constructor of searchviewmodel, initializing observablecollection of searchtabviewmodels , adding 2 tabs. first tab has "+" header , other normal search tab. tabcontrol's selectionchanged event bound method checks if "+" tab clicked. if is, new tab inserted before "+" tab , tabcontrol's selectedindex property set index of inserted tab. simple setup.
the issue i'm having when application first run, can click "+" tab , insert new tab "+" tab dead , nothing happens when click it. selectionchanged event not fire. i've checked , selectedindex set tab before it's not selected tab. fix it, have click on tab first , works fine. freezes once @ beginning.
can see issue may be? i'm including relevant portions of code:
xaml
<tabcontrol name="searchtabcontrol" itemssource="{binding path=searchtabs}" selectedindex="{binding path=selectedtabindex}" itemtemplateselector="{binding source={staticresource searchtabtemplateselector}}"> <i:interaction.triggers> <i:eventtrigger eventname="selectionchanged" > <i:invokecommandaction commandname="searchtabhaschanged" command="{binding selectionchangedcommand}" commandparameter="{binding relativesource={relativesource self}, path=commandname}"/> </i:eventtrigger> </i:interaction.triggers> ....more code
searchviewmodel
public class searchviewmodel : observableobject, ipageviewmodel { #region fields public observablecollection<searchtabviewmodel> searchtabs { get; set; } private int _selectedtabindex; private icommand _selectionchangedcommand; #endregion public searchviewmodel() { try { // initialize searchtabs array this.searchtabs = new observablecollection<searchtabviewmodel>(); // add tabitem + in header searchtabviewmodel tabadd = new searchtabviewmodel("+"); this.searchtabs.add(tabadd); // add first tab addtabitem(); selectedtabindex = 0; } catch (exception ex) { messagebox.show(ex.message); } } #region properties/commands public int selectedtabindex { { return _selectedtabindex; } set { _selectedtabindex = value; onpropertychanged("selectedtabindex"); } } public icommand selectionchangedcommand { { if (_selectionchangedcommand == null) { _selectionchangedcommand = new relaycommand( param => tabselectionchanged(param) ); } return _selectionchangedcommand; } } #endregion #region methods public void tabselectionchanged(object source) { if (source.tostring() == "searchtabhaschanged") { searchtabviewmodel tab = this.searchtabs[selectedtabindex]; if (tab != null && tab.header != null) { if (tab.header.equals("+")) { // add new tab searchtabviewmodel addedtab = addtabitem(); // select newly added tab item selectedtabindex = this.searchtabs.indexof(addedtab); } } } } private searchtabviewmodel addtabitem() { int count = searchtabs.count; // create new tab item searchtabviewmodel tab = new searchtabviewmodel(); tab.header = string.format("tab {0}", count); // insert tab item right before last (+) tab item this.searchtabs.insert(count - 1, tab); return tab; } #endregion }
also, curious behavior i've noticed when first run application , click "+" tab once add new tab , "+" tab dies, if application loses focus , gains focus again, selectionchanged event fires , new tab added? behavior happens when "+" tab dead. once fix clicking on tab, behavior disappears.
in tabselectionchanged, add new tabitem , change selectedtabindex right after each other. problem itemcontainergenerator generates new tabitem in view has not been triggered yet. done in databinding phase. when set selectedtabindex, set (already selected) + tab.
to fix this, postpone changing of selectedtabindex invoking call on dispatcher priority lower databinding.
this.dispatcher.begininvoke(() => selectedtabindex = this.searchtabs.indexof(addedtab), dispatcherpriority.background);
Comments
Post a Comment