WPF选项卡控件阻止选项卡更改

时间:2011-02-23 11:41:32

标签: c# wpf

我正在尝试为我的应用程序开发一个系统维护屏幕,其中我有几个选项卡,每个选项卡代表不同的维护选项,即维护系统用户等。一旦用户点击edit / new来更改现有记录,我想阻止导航离开当前标签,直到用户点击保存或取消。

经过一些谷歌搜索后,我找到了一个链接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;
    }
}

现在道歉,如果我是愚蠢的,但对于我的生活,我无法锻炼,看看为什么当用户在标签之间点击时我的事件不会触发。

感谢您的帮助。

埃姆林

6 个答案:

答案 0 :(得分:14)

我想出了一个适合我需求的解决方案。似乎略微倒退,但与其他选项相比,我发现它看起来很漂亮。

基本上我保留当前tabIndex的私有变量和tabControl的“SelectionChanged”事件我正在做一些检查,如果用户不处于浏览模式,则将tabControl.SelectedIndex设置回此值。 / p>

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);
            }

        }
    }

答案 1 :(得分:8)

我也在努力解决这个问题。只需添加

即可实现
IsSynchronizedWithCurrentItem="True"

设置为TabControl。之后就像一个魅力。

答案 2 :(得分:1)

根据这篇文章

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;
            }
        }
    }
}

答案 3 :(得分:0)

Josh正在使用tab.ItemsSource。您正在使用tab.Items.SourceCollection。这可能是问题所在。

答案 4 :(得分:0)

或者自己实施......

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;
    }
}

答案 5 :(得分:0)

我开始掌握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/>

在视图模型中,我有一个属性

    private EditingState _PhysicianEditingState;

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

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

希望这会有所帮助。