2010-05-03 9 views
6

Estoy construyendo una aplicación LOB que tiene una sección principal y un TabControl con varios TabItems en él. Al presionar guardar, la idea es que los campos en error se resaltan y el primer campo en error se enfoca.Silverlight TabControl - Encontrar y seleccionar un TabItem desde un Control dado en el TabItem

Si el primer, y único, campo en error está en una pestaña no seleccionada, la pestaña debe seleccionarse y el campo en error debe resaltarse y tener foco. Pero no puedo hacer que esto funcione.

Lo que parece estar sucediendo es que la pestaña No seleccionada no se encuentra en el árbol visual, por lo que no puede volver al TabItem propietario y convertirlo en el TabItem seleccionado actualmente en TabControl.

¿Alguien tiene una idea de cómo se puede lograr esto \ logrado?

Respuesta

1

Cómo lo solucioné (preguntando al arquitecto plomo) ...

Crear una ITabActivator interfaz con un método Activa.

Crea una clase derivada de Grid y ITabActivator llamada TabPageActivator. El constructor del cual toma el TabITem y el TabControl.

En lugar de agregar una Cuadrícula simple a TabItem.Contents, agregue un TabPageActivator.

Cambiar la detección de Padres de usar ...

DependencyObject matriz = _Control.Parent;

... en lugar de usar el VisualTreeHelper.

Así que cuando se desplaza la prueba Jerarquía de ...

si (los padres es TabActivator) (padre como ITabActivator) .Activate()

... así que cuando se llama Activar

m_TabControl.SelectedItem = m_TabItem; // Desde los parámetros del constructor.

... y no olvide que puede tener pestañas anidadas, por lo que debe seguir subiendo por la jerarquía.

+0

Seguramente verá todas las pestañas seleccionadas primero, antes de que se muestre su pestaña de validación final? –

+0

No, no funciona, funciona bien. Tal vez fui demasiado breve en mi explicación de la solución. Puedo explicarlo con más detalle si quieres? –

+0

small nitpick: Me pareció una muy mala idea usar constructores no predeterminados en los controles. Hace que el control no sea compatible con xaml ... – TDaver

0

Conozco un camino, pero es feo. Implica el uso de un DispatcherTimer con un intervalo de unos pocos milisegundos. En Page_Loaded, iniciarías el temporizador. Luego, en cada tilde, establece IsSelected = true para uno de los elementos de pestañas. En la siguiente marca, selecciona la siguiente pestaña, etc. hasta que se hayan seleccionado todas las pestañas. Luego, debería seleccionar el primer elemento nuevamente y matar el temporizador. Esto obligará a las imágenes en los elementos de pestañas para cargar.

También debería cubrir el TabControl con un borde o algo así durante esta operación. De lo contrario, el usuario verá todos los elementos de la pestaña rápidamente pasando rápidamente.

+0

Sí - no es una solución bastante. –

+0

Es cierto. Uso esta solución yo mismo, y me avergüenza cada vez que miro el código. :) Si tuviera que hacerlo otra vez, lo encapsularía en un comportamiento para que desaparezca. Lamentablemente, no puedo pensar en otra forma de hacer que las imágenes se rindan. –

1

Uso TabControls para la navegación en uno de mis sitios (YinYangMoney) y construí algunos métodos de extensión que me ayudan a seleccionar pestañas usando nombres de etiqueta. Aquí hay fragmentos que deberían funcionar para usted.

La clase Extensiones:

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

El XAML para su TabControl y TabItems sería algo como esto:

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

Y se puede seleccionar el TabItem Bienvenido así:

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

o

x_TabControl.SelectTab(x_WelcomeTab); 
+0

El problema es encontrar el TabItem que se va a seleccionar en función de un control que se mostrará dentro de él. –

4

para cargar el TabItem:

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

Esto hace que el tabItemOfInterest para cargar alongwith todos los controles contenidos dentro de la TabItem.

La línea de abajo por sí solo no carga el tabItemOfInterest:

tabControl.SelectedItem = tabItemOfInterest; 

Quisiera, sin embargo, estar muy interesado en el enfoque adoptado David para llegar al control erróneo.

1

Mi solución utilizando la propiedad adjunta TabItem. Crear clase 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 
} 

Siguiente hacer esto en TabControl caso carga:

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

y esto antes de enfoque de ajuste:

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