4

我有一个通过 显示的超链接列表,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

4 回答 4

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;

}
于 2010-02-26T08:37:54.720 回答
2

尝试使用ItemContainerGenerator.ContainerFromItem方法

foreach (var item in SubMenu.Items)
{ 
    var child = SubMenu.ItemContainerGenerator.ContainerFromItem(item);
    HyperlinkButton hb = child as HyperlinkButton; 
    // use hb
}
于 2010-02-26T01:46:53.727 回答
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;
}
于 2013-06-17T15:21:10.897 回答
1

试试这个:

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

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

于 2010-02-25T19:36:30.903 回答