WPF Tab Control запретить изменение вкладки

Я пытаюсь разработать экран обслуживания системы для моего приложения, в котором у меня есть несколько вкладок, каждая из которых представляет собой другой вариант обслуживания, т. е. поддерживает пользователей системы и т. д. Как только пользователь нажимает "изменить/создать", чтобы изменить существующую запись, я хочу запретить переход от текущей вкладки до тех пор, пока пользователь не нажмет "сохранить" или "отменить".

после некоторого googling я нашел ссылку http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected/

6 ответов


Я придумал решение, которое соответствует моим потребностям. Кажется немного назад, но по сравнению с другими вариантами, которые я нашел, кажется приятным и аккуратным.

в основном я сохраняю закрытую переменную текущего tabIndex и на событии "SelectionChanged" tabControl я делаю некоторые проверки и устанавливаю tabControl.SelectedIndex возвращается к этому значению, если пользователь не находится в режиме просмотра.

private void tabControl_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        if (e.OriginalSource == tabControl)
        {
            if (EditMode == TEditMode.emBrowse)
            {
                _TabItemIndex = tabControl.SelectedIndex;
            }
            else if (tabControl.SelectedIndex != _TabItemIndex) 
            {
                e.Handled = true;

                tabControl.SelectedIndex = _TabItemIndex;

                MessageBox.Show("Please Save or Cancel your work first.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
            }

        }
    }

Я тоже боролся с этим. Просто получил его работу, просто добавив

IsSynchronizedWithCurrentItem="True"

настройка TabControl. После этого сработало как по волшебству.


Джош используя tab.ItemsSource. Вы используете tab.Items.SourceCollection. Это может быть проблемой.


или выполнять его самостоятельно...

public delegate void PreviewSelectionChangedEventHandler(object p_oSender, PreviewSelectionChangedEventArgs p_eEventArgs);

public class PreviewSelectionChangedEventArgs
{
    internal PreviewSelectionChangedEventArgs(IList p_lAddedItems, IList p_lRemovedItems)
    {
        this.AddedItems = p_lAddedItems;
        this.RemovedItems = p_lRemovedItems;
    }
    public bool Cancel { get; set; }
    public IList AddedItems { get; private set; }
    public IList RemovedItems { get; private set; }
}

public class TabControl2: TabControl
{
    public event PreviewSelectionChangedEventHandler PreviewSelectionChanged;

    private int? m_lLastSelectedIndex;

    protected override void OnSelectionChanged(SelectionChangedEventArgs e)
    {
        base.OnSelectionChanged(e);

        // déterminer si on doit annuler la sélection
        PreviewSelectionChangedEventArgs eEventArgs = new PreviewSelectionChangedEventArgs(e.AddedItems, e.RemovedItems);
        if (m_lLastSelectedIndex.HasValue)
            if (PreviewSelectionChanged != null)
                PreviewSelectionChanged(this, eEventArgs);

        // annuler (ou pas) la sélection
        if (eEventArgs.Cancel)
            this.SelectedIndex = m_lLastSelectedIndex.Value;
        else
            m_lLastSelectedIndex = this.SelectedIndex;
    }
}

согласно этому сообщению

https://social.msdn.microsoft.com/Forums/vstudio/en-US/d8ac2677-b760-4388-a797-b39db84a7e0f/how-to-cancel-tabcontrolselectionchanged?forum=wpf

это сработало для меня:

<TabControl>
   <TabControl.Resources>
     <Style TargetType="TabItem">
        <EventSetter Event="PreviewMouseLeftButtonDown" 
            Handler="OnPreviewMouseLeftButtonDown"/>
     </Style>  
   </TabControl.Resources>
   <TabItem Header="Tab1"/>
   <TabItem Header="Tab2"/>
</TabControl>
private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if (e.Source is TabItem) //do not handle clicks on TabItem content but on TabItem itself
    {
        var vm = this.DataContext as MyViewModel;
        if (vm != null)
        {
            if (!vm.CanLeave())
            {
                e.Handled = true;
            }
        }
    }
}

Я начинаю понимать XAML, поэтому надеюсь, что я не пропустил вашу точку зрения. У меня была такая же проблема, и для меня это сработало лучше всего.

в XAML я определяю стиль, который переключает состояние ReadOnly

<!-- prevent the tab from being changed while editing or adding a physician -->
<Style BasedOn="{StaticResource {x:Type TabControl}}" 
        TargetType="{x:Type TabControl}" x:Key="InactivateTabControl">
    <!-- <Setter Property="IsEnabled" Value="True" /> -->
    <Style.Triggers>
        <DataTrigger Binding="{Binding PhysicianTypeTabAreLocked}" Value="False">
            <Setter Property="IsEnabled" Value="True" />
        </DataTrigger>
        <DataTrigger Binding="{Binding PhysicianTypeTabAreLocked}" Value="True">
            <Setter Property="IsEnabled" Value="False" />
        </DataTrigger>
    </Style.Triggers>
</Style>

<TabControl Grid.Row="1" Grid.Column="0" Margin="0, 10, 0, 0"
     x:Name="PhysicianTypesTabControl" 
     SelectedIndex="{Binding PhysicianTypeSelectedTabIndex, Mode=TwoWay}" 
     Style="{StaticResource InactivateTabControl}">

    <!-- rest here ....-->

 <TabControl/>

в viewmodel у меня есть свойство

    private EditingState _PhysicianEditingState;

    public EditingState PhysicianEditingState
    {
        get { return _PhysicianEditingState; }
        set
        {
            _PhysicianEditingState = value;

            PhysicianTypeTabAreLocked = (PhysicianEditingState != EditingState.NotEditing);
            NotifyPropertyChanged("PhysicianTypeTabAreLocked");
        }
    }

надеюсь, что это помогает.