List ItemsControl.Items as UIElements

I have a list of hyperlinks that are displayed through ItemsControl , something like this:

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

what I need to do is list the actual hyperlinks in the submenu, for example:

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

The problem is that I cannot find a way to list the actual user interface elements in ItemsCollection.Items.

Does anyone know how to do this or a possible workaround?

I can mention that what I am trying to do is to create a menu and submenu displaying hyperlinks clicked as a kind of crackers.

UPDATE: It would be best if I could somehow get to this stack panel, because this code works:

  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); } } } 
+4
source share
4 answers

The solution looks like this:

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

FindVisualChild Extension Method:

 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; } 
+8
source

Try using the ItemContainerGenerator.ContainerFromItem method

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

FindVisualChild from Johan Leino's answer has an error: lower level transitions in the control hierarchy have no effect, because it does not check the result of the recursive call.

This is a fixed version.

 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; } 
+2
source

Try the following:

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

This is used by the Enumerable.OfType<TResult> extension method, which filters the collection only for those elements that are of the specified type.

+1
source

Source: https://habr.com/ru/post/1302409/


All Articles