Preventing tab changes for TabControl
See original GitHub issueIf we have a TabControl
in a WPF application and we’d like to allow or not tab changes, the best way we can actually do it is by having an attached property like the following :
public static partial class TabControlHelper
{
public static readonly DependencyProperty PreventTabChangeProperty = DependencyProperty.RegisterAttached("PreventTabChange", typeof(bool), typeof(TabControlHelper), new PropertyMetadata(false, OnPreventTabChangeChanged));
public static bool GetPreventTabChange(TabControl tabControl)
{
return (bool)tabControl.GetValue(PreventTabChangeProperty);
}
public static void SetPreventTabChange(TabControl tabControl, bool value)
{
tabControl.SetValue(PreventTabChangeProperty, value);
}
private static void OnPreventTabChangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is bool preventTabChanges && d is TabControl tabControl)
{
if (preventTabChanges)
{
tabControl.SelectionChanged += TabControl_SelectionChanged;
}
else
{
tabControl.SelectionChanged -= TabControl_SelectionChanged;
}
}
}
private static void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (sender is TabControl tabControl && e.RemovedItems.Count > 0)
{
int prevIdx = tabControl.Items.IndexOf(e.RemovedItems[0]);
if (prevIdx != -1)
{
tabControl.SelectionChanged -= TabControl_SelectionChanged;
tabControl.SelectedIndex = prevIdx;
tabControl.SelectionChanged += TabControl_SelectionChanged;
}
}
}
}
It prevents tab changes properly but it has side effects : because of tabControl.SelectedIndex = prevIdx;
, Selector.SelectionChanged
is raised. Moreover the initial tab change won’t be really prevented, it’ll just be reverted and that means the initial Selector.SelectionChanged
is also triggered. In the end, the tab change has been properly “prevented” but Selector.SelectionChanged
is raised twice which is obviously not what we want.
I’m not sure about what’s the best way to implement this in WPF, I think the most natural to me would be having a boolean dependency property usable like the above attached property but without the side effects or a PreviewSelectionChanged event that allows me to cancel the change via args… As long as tab changes can be prevented without side effects it’s good.
Issue Analytics
- State:
- Created 2 years ago
- Reactions:1
- Comments:7 (7 by maintainers)
Top GitHub Comments
@Symbai the problem with that is the expectation of routing strategies.
SelectionChanged
is a bubbling event, and by convention the tunneling counter parts are prefixed withPreview
. I would find it very confusing that there would be a tunneling version of the event that you would not find by looking forPreview
name.As for past tense in names, there is
Executed
andPreviewExecuted
events onCommandManager
,Got/LostKeyboardFocus
andPreviewGot/LostKeyboardFocus
etc. There is alsoContextMenuOpening/Closing
andCopying/Pasting
but these are bubbling.I think should this be added it should be named according to the routing strategy.
@Symbai Why would you prefer
SelectionChanging
toPreviewSelectionChanged
?Either way, this is not a very user-friendly solution. The way to do this is to disable the other tabs, so that user can see that they cannot be activated, and that way no event will be fired in the first place.