2011-02-23 218 views
8

我試圖爲我的應用程序開發系統維護屏幕,其中我有幾個選項卡,每個選項卡代表不同的維護選項,即維護系統用戶等等。一旦用戶單擊編輯/新建更改現有記錄,我想阻止從當前選項卡導航,直到用戶單擊保存或取消。WPF選項卡控件防止選項卡更改

經過一些谷歌搜索後,我發現一個鏈接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; 
    } 
} 
現在

道歉,如果我是愚蠢的,但對我的生活,我不能鍛鍊明白爲什麼當用戶點擊選項卡之間我不會觸發事件。

感謝您的幫助。

埃姆林

+0

Josh的方法是行不通的對我來說也是。 – Bolu 2011-02-23 12:56:29

回答

13

我想出了一個適合我需求的解決方案。似乎稍微倒退,但與我發現的其他選項相比,看起來不錯而且整齊。

基本上我保持當前tabIndex和TabControl的「SelectionChanged」事件的私有變量我正在做一些檢查並將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); 
      } 

     } 
    } 
0

喬什使用tab.ItemsSource。您正在使用tab.Items.SourceCollection。這可能是問題所在。

+0

感謝您的建議,但由於我的標籤是xaml中的「硬編碼」,而不是由集合創建,所以對我來說這似乎不起作用。 – Emlyn 2011-02-23 12:24:16

8

我也在爲此苦苦掙扎。剛剛得到它的工作,只需將設置爲TabControl

IsSynchronizedWithCurrentItem="True" 

設置。之後就像魅力一樣工作。

+1

非常好...我們只是在這裏同樣的問題掙扎,並照顧它。謝謝! – MetalMikester 2012-03-15 12:51:52

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

我正在使用這種技術,它似乎運作良好。由於我想告訴用戶爲什麼他們不能更改標籤,我將其添加到PreviewSelectionChanged處理程序中:'if(dontAllowTabChange) { eventargs.Cancel = true; Dispatcher.BeginInvoke(new Action(()=> MessageBox.Show(「請在離開此選項卡之前保存更改。「, \t \t」Warning「, MessageBoxButton.OK,MessageBoxImage.Exclamation); })); } – Number8 2016-05-25 22:20:06

0

根據這個帖子

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; 
      } 
     } 
    } 
} 
相關問題