2010-05-03 4 views
6

Je construis une application métier qui a une section principale et un TabControl avec divers TabItems. En appuyant sur Enregistrer, l'idée est que tous les champs en erreur sont mis en surbrillance et le premier champ en erreur obtient le focus.Silverlight TabControl - Recherche et sélection d'un TabItem à partir d'un contrôle donné dans le TabItem

Si le premier et le seul champs erronés se trouvent sur un onglet Non sélectionné, l'onglet doit alors être sélectionné et le champ erroné doit être mis en surbrillance et avoir le focus. Mais je ne peux pas faire fonctionner ça. Ce qui semble se produire est que l'onglet Non sélectionné ne figure pas dans l'arborescence visuelle. Vous ne pouvez donc pas revenir au TabItem propriétaire et en faire le TabItem actuellement sélectionné dans le TabControl.

Quelqu'un at-il une idée sur la façon dont cela peut être fait?

Répondre

1

Comment je l'ai résolu (en demandant l'architecte principal) ...

Créer une interface ITabActivator avec une méthode Activer.

Créez une classe dérivée de Grid et ITabActivator appelée TabPageActivator. Le constructeur de qui prend le TabITem et le TabControl.

Au lieu d'ajouter une simple grille à TabItem.Contents, ajoutez un TabPageActivator.

Modifier la détection des parents à utiliser ...

parent DependencyObject = _Control.Parent;

... au lieu d'utiliser VisualTreeHelper.

Ainsi, lorsque vous naviguez sur le test de la hiérarchie pour ...

si (parent est TabActivator) (parent comme ITabActivator) .Activate()

... alors quand Activate est appelé

m_TabControl.SelectedItem = m_TabItem; // À partir des paramètres du constructeur.

... et n'oubliez pas que vous pouvez avoir des onglets imbriqués, donc vous devez continuer à monter dans la hiérarchie.

+0

Vous voyez certainement tous les onglets sélectionnés en premier, avant que votre onglet de validation final s'affiche? –

+0

Non, ça ne marche pas, ça marche bien. J'étais peut-être un peu trop bref dans mon explication de la solution. Je peux expliquer plus en détail si vous le souhaitez? –

+0

small nitpick: J'ai trouvé que c'était une très mauvaise idée d'utiliser des constructeurs non-défaut sur les contrôles. Cela rend le contrôle non-compatible avec xaml ... – TDaver

0

Je connais un moyen, mais c'est moche. Cela implique l'utilisation d'un DispatcherTimer avec un intervalle de quelques millisecondes. Dans Page_Loaded, vous démarrez le minuteur. Ensuite, à chaque tick, il définit IsSelected = true pour l'un des éléments de l'onglet. La coche suivante sélectionne l'onglet suivant, etc. jusqu'à ce que tous les onglets aient été sélectionnés. Ensuite, vous devrez sélectionner à nouveau le premier élément et tuer le chronomètre. Cela forcera les visuels dans les éléments de l'onglet à charger.

Vous devrez également couvrir le TabControl avec une bordure ou quelque chose pendant cette opération. Sinon, l'utilisateur verra rapidement tous les éléments de l'onglet.

+0

Ouais - pas une solution assez. –

+0

True. J'utilise cette solution moi-même, et cela me fait grincer des dents à chaque fois que je regarde le code. :) Si je devais le faire à nouveau je l'encapsulerais dans un comportement pour le rendre hors de vue. Malheureusement je ne peux pas penser à une autre façon de rendre les visuels. –

1

J'utilise TabControls pour la navigation sur un de mes sites (YinYangMoney) et construit quelques méthodes d'extension qui m'aident à sélectionner des onglets en utilisant des noms de Tag. Voici des extraits qui devraient fonctionner pour vous.

La classe Extensions:

using System; 
using System.Linq; 
using System.Windows.Controls; 

namespace MyApplication 
{ 
    internal static class Extensions 
    { 
     // Extension for TabControl 
     internal static void SelectTab(this TabControl tabControl, this TabItem tabItem) 
     { 
      if (tabControl == null || tabItem == null) 
       return null; 

      SelectTab(tabControl, tabItem.Tag); 
     } 

     // Extension for TabControl 
     internal static void SelectTab(this TabControl tabControl, string tabTagName) 
     { 
      if (tabControl == null) 
       return null; 

      // Find the TabItem by its Tag name 
      TabItem mainTabItem = tabControl.FindByTag(tabTagName); 
      if (mainTabItem == null) 
       return; 

      // Check to see if the tab needs to be selected 
      if (tabControl.SelectedItem != mainTabItem) 
       tabControl.SelectedItem = mainTabItem; 
     } 

     // Extension for TabControl 
     internal static TabItem FindByTag(this TabControl tabControl, string tagFragment) 
     { 
      if (tabControl == null || tagFragment == null) 
       return null; 

      return tabControl.Items 
        .OfType<TabItem>() 
        .Where(item => item.Tag != null && item.Tag.ToString().StartsWithIgnoreCase(tagFragment)) 
        .FirstOrDefault(); 
     } 

     // Extension for string 
     internal static bool StartsWithIgnoreCase(this string source, string target) 
     { 
      return source.StartsWith(target, StringComparison.CurrentCultureIgnoreCase); 
     } 
    } 
} 

Le XAML pour votre TabControl et TabItems ressemblerait à quelque chose comme ceci:

<Controls:TabControl x:Name="x_TabControl"> 
    <Controls:TabItem Header="Welcome" Tag="/Home/Welcome" x:Name="x_WelcomeTab" /> 
    <Controls:TabItem Header="FAQ" Tag="/Home/FAQ" /> 
    <Controls:TabItem Header="Contact Us" Tag="/Home/Contact_Us" /> 
    <Controls:TabItem Header="Privacy Policy" Tag="/Home/Privacy_Policy" /> 
    <Controls:TabItem Header="My Account" Tag="/Home/My_Account" /> 
</Controls:TabControl> 

Et vous pouvez sélectionner la bienvenue TabItem comme ceci:

x_TabControl.SelectTab("/Home/Welcome"); 

ou

x_TabControl.SelectTab(x_WelcomeTab); 
+0

Le problème est de trouver le TabItem qui doit être sélectionné en fonction d'un contrôle qui sera affiché dedans. –

4

Pour charger le TabItem:

tabControl.SelectedItem = tabItemOfInterest; 
tabControl.UpdateLayout(); 

Cela provoque le tabItemOfInterest à charger alongwith tous les contrôles contenus dans le TabItem.

La ligne ci-dessous ne pas le seul charges tabItemOfInterest: cependant,

tabControl.SelectedItem = tabItemOfInterest; 

Je, très intéressé par l'approche David adoptée pour obtenir le contrôle erroné.

1

Ma solution utilisant la propriété attachée TabItem. Créer une classe TabItemExtender:

/// <summary> 
/// TabItem Extender class with TabItem property 
/// </summary> 
public class TabItemExtender 
{ 
    #region property getters/setters 
    /// <summary> 
    /// TabItem attached dependency property 
    /// </summary> 
    public static readonly DependencyProperty TabItemProperty = DependencyProperty.RegisterAttached("TabItem", typeof(TabItem), typeof(TabItemExtender), null); 

    /// <summary> 
    /// TabItem Property getter 
    /// </summary> 
    public static TabItem GetNavigateUri(DependencyObject source) 
    { 
     return (TabItem)source.GetValue(TabItemExtender.TabItemProperty); 
    } 

    /// <summary> 
    /// TabItem Property setter 
    /// </summary> 
    public static void SetNavigateUri(DependencyObject target, TabItem value) 
    { 
     target.SetValue(TabItemExtender.TabItemProperty, value); 
    } 
    #endregion 
} 

Suivant faire sur TabControl événement de chargement:

private void ExtendedTabControl_Loaded(object sender, System.Windows.RoutedEventArgs e) 
{ 
    foreach (object item in this.Items) 
    { 
     var tabItem = item as TabItem; 
     if (tabItem != null && tabItem.Content != null) 
     { 
      var element = (FrameworkElement)tabItem.Content; 
      element.SetValue(TabItemExtender.TabItemProperty, tabItem); 
     } 
    } 
} 

et cela avant de se concentrer:

var element = (UIElement)control; 
while (element != null) 
{ 
    //Get TabItem 
    var tabItem = (TabItem)element.GetValue(TabItemExtender.TabItemProperty); 

    if (tabItem != null) 
    { 
     if (!tabItem.IsSelected && tabItem.IsEnabled) 
     { 
      tabItem.IsSelected = true; 
      ((TabControl)tabItem.Parent).UpdateLayout(); 
     } 

     break; 
    } 

    element = (UIElement)VisualTreeHelper.GetParent(element); 
} 

control.Focus(); 
Questions connexes