将ItemsControl.Items枚举为UIElements

时间:2010-02-25 19:33:46

标签: silverlight itemscontrol uielement

我有一个通过ItemsControl显示的超链接列表,如下所示:

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

我需要做的是枚举子菜单中的实际超链接,如下所示:

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

问题是我似乎找不到枚举ItemsCollection.Items中实际UI元素的方法。

任何人都知道如何执行此操作或可能的解决方法?

我可以提一下,我想要做的是建立一个菜单和子菜单,显示点击的超链接作为一种面包屑。

更新 最好的办法是,如果我能以某种方式到达那个堆栈面板,因为这段代码似乎有效:

    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 个答案:

答案 0 :(得分:8)

解决方案如下所示:

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:

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;

}

答案 1 :(得分:2)

尝试使用ItemContainerGenerator.ContainerFromItem方法

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

答案 2 :(得分:2)

来自Johan Leino的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;
            }

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

    return control;
}

答案 3 :(得分:1)

试试这个:

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

这是使用Enumerable.OfType<TResult>扩展方法将集合过滤到仅指定类型的项目。