2011-02-23 9 views
8

Estoy tratando de desarrollar una pantalla de mantenimiento del sistema para mi aplicación en la que tengo varias pestañas cada una representando una opción de mantenimiento diferente, es decir, mantener a los usuarios del sistema, etcétera. Una vez que un usuario hace clic en editar/nuevo para cambiar un registro existente, quiero evitar que navegue fuera de la pestaña actual hasta que el usuario haga clic en guardar o cancelar.WPF Control de ficha Prevenir cambio de pestaña

Después de buscar en Google he encontrado un enlace http://joshsmithonwpf.wordpress.com/2009/09/04/how-to-prevent-a-tabitem-from-being-selected/ que parecía resolver mi problema, o al menos eso pensaba.

He intentado implementar esto, pero mi evento parece que nunca se dispara. A continuación está mi 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> 

Y este es mi código

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

Disculpas ahora si estoy siendo estúpido, pero para la vida de mí no puedo entrenamiento ver por qué mi evento no se dispara cuando el usuario hace clic en una pestaña a otra .

Gracias por su ayuda.

Emlyn

+0

de Josh no está funcionando para mí tampoco. – Bolu

Respuesta

13

He encontrado una solución que se adapta a mis necesidades. Parece ligeramente hacia atrás, pero en comparación con las otras opciones que me parece parece agradable y ordenada.

Básicamente, mantengo una variable privada del tabIndex actual y en el evento "SelectionChanged" de tabControl estoy haciendo algunas comprobaciones y establezco el tabControl.SelectedIndex en este valor si el usuario no está en modo exploración.

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

Josh está utilizando tab.ItemsSource. Usted está usando tab.Items.SourceCollection. Este podría ser el problema.

+0

Gracias por esta sugerencia, pero como mis pestañas están "Codificadas" en la xaml y no creadas por una colección, esto no me parece útil. – Emlyn

8

Yo estaba luchando con esto también. Acabo de hacerlo funcionar simplemente agregando el

IsSynchronizedWithCurrentItem="True" 

estableciendo en el TabControl. Trabajó como un encanto después de eso.

+1

Excelente ... Estábamos luchando con el mismo problema aquí y eso se encargó. ¡Gracias! – MetalMikester

0

o implementar por sí mismo ...

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

Estoy usando esta técnica, y parece funcionar bien. Como quería decirle al usuario por qué no pueden cambiar las pestañas, lo agregué al controlador PreviewSelectionChanged: 'if (dontAllowTabChange) { eventargs.Cancel = true; Dispatcher.BeginInvoke (nueva Acción (() => { MessageBox.Show ("Guarda los cambios antes de salir de esta pestaña.", \t \t" Advertencia ", MessageBoxButton.OK, MessageBoxImage.Exclamation); })); }' – Number8

0

De acuerdo con este post

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

esto funcionó para mí: Método

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