Найти элемент управления внутри ListBox? - PullRequest
1 голос
/ 05 ноября 2010
   <Style TargetType="ListBoxItem" x:Key="ListBoxItemTemplate">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <Button Content="{TemplateBinding Content}"></Button>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>     
    <ListBox ItemsSource="{Binding S}" 
             x:Name="listBox" 
             ItemContainerStyle="{StaticResource ListBoxItemTemplate}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <UniformGrid x:Name="grid" Columns="5"></UniformGrid>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>

Я хочу найти "сетку" из элемента управления ListBox. Пожалуйста, помогите мне, спасибо.

Ответы [ 2 ]

10 голосов
/ 05 ноября 2010

Несколько вещей, которые нужно добавить к ответу Мелеака (и это было слишком долго, чтобы добавить комментарий).

Обычно способ получения именованного элемента из шаблона в WPF - это вызовметод FindName шаблона.Однако, поскольку шаблоны в основном являются фабриками, вам также необходимо указать, какой конкретный экземпляр шаблона вам требуется - один экземпляр ItemsPanelTemplate мог быть создан несколько раз.Так что вам нужно что-то вроде этого:

var grid = (UniformGrid) listBox.ItemsPanel.FindName("grid", ???);

Но что в этом такого ???заполнитель?Это не сам ListBox - ListBox на самом деле не использует эту ItemsPanel напрямую.В конечном счете, он используется ItemsPresenter в шаблоне ListBox.Так что вам нужно сделать это:

var grid = (UniformGrid) listBox.ItemsPanel.FindName("grid", myItemsPresenter);

... за исключением того, что нет надежного способа завладеть ItemsPresenter.На самом деле их может даже не быть - законно создать шаблон для ListBox, который просто предоставляет панель хостинга напрямую - для этой цели есть даже специальное свойство Panel.IsItemsHost.приводит ко второму пункту, который я хотел добавить.В тех случаях, когда шаблон ListBox не использует ItemsPresenter, панель ItemsPanel не будет использоваться.Таким образом, вполне возможно, что UniformGrid, который вы пытаетесь получить, даже не существует.

4 голосов
/ 05 ноября 2010

Один из способов сделать это - сохранить его в коде после его загрузки.

<ListBox ItemsSource="{Binding S}"  
         x:Name="listBox"  
         ItemContainerStyle="{StaticResource ListBoxItemTemplate}"> 
    <ListBox.ItemsPanel> 
        <ItemsPanelTemplate> 
            <UniformGrid x:Name="grid" Columns="5" Loaded="grid_Loaded"></UniformGrid> 
        </ItemsPanelTemplate> 
    </ListBox.ItemsPanel> 
</ListBox> 

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

private UniformGrid m_uniformGrid = null;  
private void grid_Loaded(object sender, RoutedEventArgs e) 
{ 
    m_uniformGrid = sender as UniformGrid; 
} 

Если вы хотите найти его в ListBox, вы можете использовать Visual Tree.

UniformGrid uniformGrid = GetVisualChild<UniformGrid>(listBox);

public static T GetVisualChild<T>(object parent) where T : Visual
{
    DependencyObject dependencyObject = parent as DependencyObject;
    return InternalGetVisualChild<T>(dependencyObject);
}
private static T InternalGetVisualChild<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;
}
...