Перечислите ItemsControl.Items как UIElements - PullRequest
4 голосов
/ 25 февраля 2010

У меня есть список гиперссылок, которые отображаются через 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.

Кто-нибудь знает, как это сделать или возможный обходной путь?

Я могу упомянуть, что я пытаюсь создать меню и подменю, которые отображают гиперссылки, нажимаемые в виде некой хлебной крошки.

UPDATE: Лучше всего было бы, если бы я мог как-то добраться до этой панели стека, потому что этот код, кажется, работает:

    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 ]

8 голосов
/ 26 февраля 2010

Решение выглядит так:

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;

}
2 голосов
/ 17 июня 2013

FindVisualChild от Johan Leino в ответе есть ошибка: обход нижних уровней в иерархии элементов управления не имеет никакого эффекта, потому что он не проверяет результат рекурсивного вызова.

Это исправленная версия.

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 голосов
/ 26 февраля 2010

Попробуйте использовать метод ItemContainerGenerator.ContainerFromItem

foreach (var item in SubMenu.Items)
{ 
    var child = SubMenu.ItemContainerGenerator.ContainerFromItem(item);
    HyperlinkButton hb = child as HyperlinkButton; 
    // use hb
}
1 голос
/ 25 февраля 2010

Попробуйте это:

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

Используется метод расширения Enumerable.OfType<TResult>, который фильтрует коллекцию только до тех элементов, которые относятся к указанному типу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...