2010-02-25 19 views
4

UIElements J'ai une liste de liens hypertextes qui sont affichés par un ItemsControl, quelque chose comme ceci:ItemsControl.Items Énumérer comme

<ItemsControl x:Name="SubMenu" Visibility="Collapsed"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <HyperlinkButton Content="{Binding Name}" 
           NavigateUri="{Binding Url}" 
           TargetName="ContentFrame" 
           Style="{StaticResource LinkStyle}" 
           /> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <StackPanel Style="{StaticResource LinksStackPanelStyle}" 
          VerticalAlignment="Center" 
          HorizontalAlignment="Left" /> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
    </ItemsControl> 

ce que je dois faire est d'énumérer les hyperliens réels dans le sous-menu, quelque chose comme ça :

foreach (UIElement child in SubMenu.Items) // this does not work! 
    { 
     HyperlinkButton hb = child as HyperlinkButton; 
     if (hb != null && hb.NavigateUri != null) 
     { 
      if (hb.NavigateUri.ToString().Equals(e.Uri.ToString())) 
      { 
       VisualStateManager.GoToState(hb, "ActiveLink", true); 
      } 
      else 
      { 
       VisualStateManager.GoToState(hb, "InactiveLink", true); 
      } 
     } 
    } 

Le problème est que je ne peux pas l'air de trouver un moyen d'énumérer les éléments d'interface utilisateur réels dans les ItemsCollection.Items.

Quelqu'un sait-il comment faire ou une solution de contournement possible?

Je peux mentionner que ce que j'essaie de faire est de construire un menu et un sous-menu qui affichent les hyperliens cliqués comme une sorte de fil d'Ariane.

MISE À JOUR: La meilleure chose serait si je pouvais arriver à ce StackPanel en quelque sorte parce que ce code semble fonctionner:

foreach (UIElement child in LinksStackPanel.Children) 
    { 
     HyperlinkButton hb = child as HyperlinkButton; 
     if (hb != null && hb.NavigateUri != null) 
     { 
      if (hb.NavigateUri.ToString().Equals(e.Uri.ToString())) 
      { 
       VisualStateManager.GoToState(hb, "ActiveLink", true); 
      } 
      else 
      { 
       VisualStateManager.GoToState(hb, "InactiveLink", true); 
      } 
     } 
    } 

Répondre

8

La solution ressemble à ceci:

foreach (var item in SubMenu.Items) 
{ 
    var hb = SubMenu.ItemContainerGenerator.ContainerFromItem(item).FindVisualChild<HyperlinkButton>(); 

    if (hb.NavigateUri.ToString().Equals(e.Uri.ToString())) 
    { 
     VisualStateManager.GoToState(hb, "ActiveLink", true); 
    } 
    else 
    { 
     VisualStateManager.GoToState(hb, "InactiveLink", true); 
    } 
} 

La méthode d'extension FindVisualChild:

public static T FindVisualChild<T>(this DependencyObject instance) where T : DependencyObject 
{ 
    T control = default(T); 

    if (instance != null) 
    { 

     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(instance); i++) 
     { 
      if ((control = VisualTreeHelper.GetChild(instance, i) as T) != null) 
      { 
       break; 
      } 

      control = FindVisualChild<T>(VisualTreeHelper.GetChild(instance, i)); 
     } 
    } 

    return control; 

} 
+0

Cela mérite plus de votes. Il suffit de placer sur le net, j'ai trouvé la solution après avoir cherché un jour. –

1

Essayez ceci:

foreach (UIElement child in SubMenu.Items.OfType<UIElement>()) 

est d'utiliser la Enumerable.OfType<TResult> méthode d'extension qui filtre la collection uniquement vers les éléments du type spécifié.

+0

Non, désolé, cela ne fonctionne pas. Il semble que les éléments dans les éléments ne sont pas les éléments d'interface utilisateur réels. Items contient typeof (MenuItem) qui est l'objet métier que j'utilise pour lier à la collection. –

2

Essayez d'utiliser la méthode ItemContainerGenerator.ContainerFromItem

foreach (var item in SubMenu.Items) 
{ 
    var child = SubMenu.ItemContainerGenerator.ContainerFromItem(item); 
    HyperlinkButton hb = child as HyperlinkButton; 
    // use hb 
} 
+0

+1 Vous étiez à peu près juste et m'a aidé en cours de route. Je l'ai résolu un peu différemment. Voir ma propre réponse à la question. Merci! –

2

FindVisualChild de réponse Johan Leino a bug: déplacement des niveaux inférieurs dans la hiérarchie de contrôle n'a aucun effet soit parce qu'il ne vérifie pas le résultat de l'appel récursif.

C'est la version corrigée.

public static T FindVisualChild<T>(this DependencyObject instance) where T : DependencyObject 
{ 
    T control = default(T); 

    if (instance != null) 
    { 
     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(instance); i++) 
     { 
      if ((control = VisualTreeHelper.GetChild(instance, i) as T) != null) 
      { 
       break; 
      } 

      if ((control = FindVisualChild<T>(VisualTreeHelper.GetChild(instance, i))) != null) 
      { 
       break; 
      } 
     } 
    } 

    return control; 
}