doull
doull

Reputation: 121

Find Control Inside ListBox?

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

I want to Find "grid" from ListBox Control.Please Help Me,Thank you.

Upvotes: 3

Views: 4126

Answers (2)

Ian Griffiths
Ian Griffiths

Reputation: 14567

A couple of things to add to Meleak's answer (and this was a bit too long to put in a comment.)

Normally, the way you obtain a named element from a template in WPF is to call the template's FindName method. However, because templates are basically factories, you also needs to say which particular instance of the template you require - a single ItemsPanelTemplate may have been instantiated several times over. So you'd need something like this:

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

But what goes in that ??? placeholder? It's not the ListBox itself - the ListBox doesn't actually use that ItemsPanel directly. Ultimately, the it's used by the ItemsPresenter in the ListBox's template. So you'd need to do this:

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

...except, there's no reliable way to get hold of the ItemsPresenter either. In fact, there might not even be one - it's legal to create a template for a ListBox that just provides the hosting panel directly - there's even a special property, Panel.IsItemsHost, for this very purpose.

And that leads onto the second point I wanted to add. In scenarios where the ListBox's template doesn't use the ItemsPresenter, the ItemsPanel will go unused. So it's actually possible that the UniformGrid you're trying to get hold of doesn't even exist.

Upvotes: 11

Fredrik Hedblad
Fredrik Hedblad

Reputation: 84674

One way to do it is to store it in code behind once it is Loaded.

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

And in code behind

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

If you want to find it from the ListBox then you can use the 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;
}

Upvotes: 6

Related Questions