WPF Tab Control Запретить изменение вкладки - PullRequest
11 голосов
/ 23 февраля 2011

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

После некоторого поиска я нашел ссылку http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected/, которая, казалось, решила мою проблему, или я так подумал.

Я пытался реализовать это, но мое мероприятие никогда не срабатывает. Ниже мой XAML.

<TabControl Name="tabControl">
    <TabItem Header="Users">
        <DockPanel>
            <GroupBox Header="Existing Users" Name="groupBox1" DockPanel.Dock="Top" Height="50">
                <StackPanel Orientation="Horizontal">
                    <Label Margin="3,3,0,0">User:</Label>
                    <ComboBox Width="100"  Height="21" Margin="3,3,0,0"></ComboBox>
                    <Button Width="50" Height="21" Margin="3,3,0,0" Name="btnUsersEdit" Click="btnUsersEdit_Click">Edit</Button>
                    <Button Width="50" Height="21" Margin="3,3,0,0" Name="btnUsersNew" Click="btnUsersNew_Click">New</Button>
                </StackPanel>
            </GroupBox>
            <GroupBox Header="User Information" Name="groupBox2">
                <Button Content="Cancel" Height="21" Name="btnCancel" Width="50" Click="btnCancel_Click" />
            </GroupBox>
        </DockPanel>
    </TabItem>
    <TabItem Header="User Groups">

    </TabItem>        
</TabControl>

А это мой код

public partial class SystemMaintenanceWindow : Window
{

    private enum TEditMode { emEdit, emNew, emBrowse }

    private TEditMode _EditMode = TEditMode.emBrowse;        

    private TEditMode EditMode
    {
        get { return _EditMode; }
        set 
        { 
            _EditMode = value; 
        }
    }        

    public SystemMaintenanceWindow()
    {
        InitializeComponent();

        var view = CollectionViewSource.GetDefaultView(tabControl.Items.SourceCollection);
        view.CurrentChanging += this.Items_CurrentChanging;
    }        

    void Items_CurrentChanging(object sender, CurrentChangingEventArgs e)
    {
        if ((e.IsCancelable) && (EditMode != TEditMode.emBrowse))
        {
            var item = ((ICollectionView)sender).CurrentItem;
            e.Cancel = true;
            tabControl.SelectedItem = item;

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

    private void btnUsersNew_Click(object sender, RoutedEventArgs e)
    {
        EditMode = TEditMode.emNew;
    }

    private void btnUsersEdit_Click(object sender, RoutedEventArgs e)
    {
        EditMode = TEditMode.emEdit;
    }

    private void btnCancel_Click(object sender, RoutedEventArgs e)
    {
        EditMode = TEditMode.emBrowse;
    }
}

Прошу прощения, если я глуп, но из-за своей жизни я не могу тренироваться, чтобы понять, почему мое событие не срабатывает, когда пользователь нажимает между вкладками.

Спасибо за вашу помощь.

Emlyn

Ответы [ 6 ]

15 голосов
/ 23 февраля 2011

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

Обычно я сохраняю приватную переменную текущего 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);
            }

        }
    }
9 голосов
/ 28 февраля 2012

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

IsSynchronizedWithCurrentItem="True"

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

1 голос
/ 13 сентября 2016

Согласно этому посту

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;
            }
        }
    }
}
0 голосов
/ 16 августа 2018

Я начинаю понимать 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");
        }
    }

Надеюсь, это поможет.

0 голосов
/ 15 августа 2014

Или реализуй это сам ...

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;
    }
}
0 голосов
/ 23 февраля 2011

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...