Как получить ListBox ItemsPanel в коде позади - PullRequest
14 голосов
/ 06 сентября 2011

У меня есть ListBox с ItemsPanel

<Setter Property="ItemsPanel">
    <Setter.Value>
        <ItemsPanelTemplate>
             <StackPanel x:Name="ThumbListStack" Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </Setter.Value>
</Setter>

Я хочу переместить панель стека вдоль оси X, используя TranslateTransform в коде позади.

Проблема в том, что я могуПанель стека.

ThumbListBox.FindName("ThumbListStack")

Ничего не возвращает.Я хочу использовать его в:

Storyboard.SetTarget(x, ThumbListBox.FindName("ThumbListStack"))

Как получить панель стека, чтобы затем использовать ее с TranslateTransform

Спасибо

Ответы [ 3 ]

22 голосов
/ 06 сентября 2011

Вы можете использовать событие Loaded для StackPanel, которое находится в ItemsPanelTemplate

<Grid>
    <Grid.Resources>
        <Style TargetType="ListBox">
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <StackPanel x:Name="ThumbListStack" Orientation="Horizontal"
                                    Loaded="StackPanel_Loaded" />
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Grid.Resources>
    <ListBox />
</Grid>

И затем в коде позади

private StackPanel m_itemsPanelStackPanel;
private void StackPanel_Loaded(object sender, RoutedEventArgs e)
{
    m_itemsPanelStackPanel = sender as StackPanel;
}

Другой способ - пройти по Визуальному дереву и найти StackPanel, который будет первым потомком ItemsPresenter.

public void SomeMethod()
{
    ItemsPresenter itemsPresenter = GetVisualChild<ItemsPresenter>(listBox);
    StackPanel itemsPanelStackPanel = GetVisualChild<StackPanel>(itemsPresenter);
}

private static T GetVisualChild<T>(DependencyObject parent) where T : Visual
{
    T child = default(T);

    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    {
        Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
        {
            child = GetVisualChild<T>(v);
        }
        if (child != null)
        {
            break;
        }
    }
    return child;
}
.
3 голосов
/ 06 сентября 2011

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

public static T FindChild<T>(this FrameworkElement obj, string name)
{
    DependencyObject dep = obj as DependencyObject;
    T ret = default(T);

    if (dep != null)
    {
        int childcount = VisualTreeHelper.GetChildrenCount(dep);
        for (int i = 0; i < childcount; i++)
        {
            DependencyObject childDep = VisualTreeHelper.GetChild(dep, i);
            FrameworkElement child = childDep as FrameworkElement;

            if (child.GetType() == typeof(T) && child.Name == name)
            {
                ret = (T)Convert.ChangeType(child, typeof(T));
                break;
            }

            ret = child.FindChild<T>(name);
            if (ret != null)
                break;
        }
    }
    return ret;
}

Проверяет всех детей и детей детей, сравнивая тип и имя, заданные на элементе управления. Используйте это так:

StackPanel ipanel = ThumbListBox.FindChild<StackPanel>("ThumbListStack");
if(ipanel == null)
    MessageBox.Show("couldn't find anything");
else
    MessageBox.Show("Aha! Found: " ipanel.Name);
1 голос
/ 06 сентября 2011

Попробуйте следующий метод расширения:

var childStackPanels = FindVisualChildren<StackPanel>(ThumbListBox);

Сам метод:

public static IEnumerable<T> FindVisualChildren<T>(this DependencyObject depObj) where T : DependencyObject
{
    if (depObj != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            var typedChild = child as T;
            if (typedChild != null)
            {
                yield return typedChild;
            }    

            foreach (T childOfChild in FindVisualChildren<T>(child))
            {
                yield return childOfChild;
            }
        }
    }
}

PS: Вы можете самостоятельно расширить его для проверки конкретного имени элемента управления, чтобы метод возвращал один элемент управления вместо списка.

...