Hello. I am implementing an app based on the MVVM pattern. One of my controls has a dockmanager with a tabgrouppane. I need to be able to change the active tab based on a property in my viewmodel. Here's what the xaml looks like:
ObjectDataProvider def:
<Window.Resources> <ResourceDictionary>
<ObjectDataProvider x:Key="odpWizard" ObjectType="{x:Type ViewModel:WizardViewModel}" IsAsynchronous="True" />...
TabGroupPane def:
<igDock:TabGroupPane x:Name="tabGroup1" SelectionChanged="tabGroup1_SelectionChanged" DataContext="{Binding Source={StaticResource odpWizard}}" SelectedIndex="{Binding ActiveTab}">...
ViewModel def;
private int _activeTab;
public int ActiveTab { get { return _activeTab; } set { _activeTab = value; OnPropertyChanged("ActiveTab"); } }
What I'm missing is how to change the active tab from the ViewModel. Thanks for the help.
Andrew,
You asked: "I'm assuming that the DataContext of the tabgroup (directly or because it is inherited from an ancestor) is your viewmodel?"
The answer is yes. I've tested that I can set the active tab via the SelectedIndex property in the XAML of the tabgrouppane definition as well as from another user control. What I'm still having trouble with is setting the ActiveTab from the viewmodel. Here's my viewmodel code:
public class WizardViewModel : INotifyPropertyChanged { #region Private Members private int _activeTab; private ICommand _setActiveTabCommand; #endregion #region Public Properties public int ActiveTab { get { return _activeTab; } set { _activeTab = value; OnPropertyChanged("ActiveTab"); } } public ICommand SetActiveTabCommand { get { return _setActiveTabCommand; } } #endregion #region Ctor public WizardViewModel(int selectedTab) { // Wire up command _setActiveTabCommand = new RelayCommand { CanExecuteDelegate = x => true, ExecuteDelegate = x => SetActiveTab(selectedTab) }; } #endregion #region Private Members public void SetActiveTab(int tab) { ActiveTab = tab; } #endregion #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } #endregion // INotifyPropertyChanged Members
byronking said: Thanks for the response, Andrew. The way the tabs are within my DockManager, I am not allowing for removal of the tabs. That said, how do I set the binding between the viewmodel and the tabgrouppane on the view? Just setting the ActiveTab property from my viewmodel does not seem to do the trick. My tabgrouppane's selectedindex property is bound to my ActiveTab property. Is that correct?
Thanks for the response, Andrew. The way the tabs are within my DockManager, I am not allowing for removal of the tabs. That said, how do I set the binding between the viewmodel and the tabgrouppane on the view? Just setting the ActiveTab property from my viewmodel does not seem to do the trick. My tabgrouppane's selectedindex property is bound to my ActiveTab property. Is that correct?
Ok so you don't allow dragging, floating, closing or unpinning?
byronking said:That said, how do I set the binding between the viewmodel and the tabgrouppane on the view? Just setting the ActiveTab property from my viewmodel does not seem to do the trick. My tabgrouppane's selectedindex property is bound to my ActiveTab property. Is that correct?
The binding seemed ok. I'm assuming that the DataContext of the tabgroup (directly or because it is inherited from an ancestor) is your viewmodel? The only thing I can think is that if keyboard focus is within another element within the tab we may be ensuring that the active/focused tab is the selected tab and setting the selected index back in which case the only option would be to use the request bring into view and then focus an element within the pane (or the pane itself) or use the Activate method of the pane.
If you are binding the SelectedIndex to your ActiveTab property then in theory you can just set your ActiveTab property and the SelectedIndex should be updated. That being said, you may not want to go this route. When an end user drags a pane, unpins a pane, floats a pane, etc. that pane will no longer be within that TabGroupPane. It may go back there depending on the interaction - e.g. when it is pinned it will be back in the container from which it was unpinned but if it is dragged out then it will be within whatever parent they dragged the pane into.
If you want to bring an element into view then you can use the BringIntoView method of an element within the pane you want to bring into view. If it happens to be within a TabGroupPane then it will be made the selected item of that tabgroup. Note active and selected are not necessarily the same thing since you can have multiple tabgroups each with a selected item but only 1 or even none may be active. The ActivePane is the one that has keyboard focus so if you want to make something the active pane then you would call Focus on it (note it would need to be brought into view in order for the WPF framework to allow you to give it focus so you might need to call BringIntoView, UpdateLayout and then Focus).