2010-05-03 14 views
6

Sto costruendo un'applicazione LOB che ha una sezione principale e una TabControl con vari TabItem in essa contenuti. Al momento del salvataggio, l'idea è che tutti i campi in errore sono evidenziati e il primo campo in errore viene messo a fuoco.Silverlight TabControl - Ricerca e selezione di un oggetto TabItem da un determinato controllo nel TabItem

Se il primo, e solo, campo in errore si trova su una scheda Deselezionata, la scheda dovrebbe quindi essere selezionata e il campo in errore dovrebbe essere evidenziato e messo a fuoco. Ma non riesco a farlo funzionare.

Ciò che sembra accadere è che la scheda Deselezionata non si trova nell'albero visivo, quindi non è possibile tornare al TabItem proprietario e impostarlo come TabItem attualmente selezionato in TabControl.

Qualcuno ha un'idea di come questo può essere fatto \ raggiunto?

risposta

1

Come ho risolto (chiedendo al Lead Architect) ...

creare un'interfaccia ITabActivator con un metodo Activate.

Creare una classe derivata da Grid e ITabActivator denominata TabPageActivator. Il costruttore di cui prende il TabITem e il TabControl.

Invece di aggiungere una semplice griglia a TabItem.Contents, aggiungere un oggetto TabPageActivator.

Modificare il rilevamento Parent da usare ...

DependencyObject genitore = _Control.Parent;

... anziché utilizzare VisualTreeHelper.

Così, quando si naviga il test Gerarchia per ...

se (genitore è TabActivator) (genitore come ITabActivator) .Activate()

... così quando Activate viene chiamato

m_TabControl.SelectedItem = m_TabItem; // Dai parametri del costruttore.

... e non dimenticare che potresti avere schede annidate, quindi devi continuare a risalire la Gerarchia.

+0

Sicuramente vedi ogni scheda selezionata per prima, prima che venga visualizzata la scheda di convalida finale? –

+0

No, non funziona, funziona bene. Ero forse un po 'troppo breve nella mia spiegazione della soluzione. Posso spiegarmi più dettagliatamente se desideri? –

+0

nitpick piccolo: ho trovato una pessima idea usare i costruttori non predefiniti sui controlli. Rende il controllo non-xaml amichevole ... – TDaver

0

Conosco un modo, ma è brutto. Implica l'uso di DispatcherTimer con un intervallo di pochi millisecondi. In Page_Loaded avresti avviato il timer. Quindi su ogni spunta imposta IsSelected = true per uno degli elementi della scheda. Al prossimo segno seleziona la voce successiva della scheda ecc. Fino a quando tutte le schede sono state selezionate. Quindi dovresti selezionare nuovamente il primo elemento e uccidere il timer. Ciò costringerà le immagini negli elementi della scheda da caricare.

Si dovrebbe anche coprire il TabControl con un bordo o qualcosa durante questa operazione. In caso contrario, l'utente vedrà tutti gli elementi della scheda sfogliati rapidamente.

+0

Sì - non è una bella soluzione. –

+0

Vero. Io uso questa soluzione da solo, e mi fa rabbrividire ogni volta che guardo il codice. :) Se dovessi farlo di nuovo, lo incoraggerei in un comportamento per farlo scomparire. Sfortunatamente non riesco a pensare a un altro modo per rendere il rendering delle immagini. –

1

Uso TabControls per la navigazione su uno dei miei siti (YinYangMoney) e ho sviluppato alcuni metodi di estensione che mi aiutano a selezionare le schede utilizzando i nomi di tag. Ecco alcuni frammenti che dovrebbero funzionare per te.

La classe estensioni:

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

Il XAML per il vostro TabControl e TabItems sarebbe simile a questa:

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

E si può selezionare il TabItem benvenuto in questo modo:

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

o

x_TabControl.SelectTab(x_WelcomeTab); 
+0

Il problema è trovare il TabItem che deve essere selezionato sulla base di un controllo che verrà mostrato al suo interno. –

4

Per caricare la TabItem:

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

Questo fa sì che il tabItemOfInterest per caricare alongwith tutti i controlli contenuti all'interno del TabItem.

La riga sotto da solo non carica il tabItemOfInterest:

tabControl.SelectedItem = tabItemOfInterest; 

Vorrei, tuttavia, essere molto interessati nell'approccio adottato David per arrivare al controllo errato.

1

La mia soluzione utilizzando la proprietà allegata TabItem. Creare 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 
} 

Avanti fare questo su TabControl evento carico:

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

e questo prima messa a fuoco impostare:

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