Finding control within WPF itemscontrol

落花浮王杯 提交于 2019-11-26 20:26:28

Using the ItemContainerGenerator you can obtain the generated container for an item and traverse the visual tree downwards to find your TextBox. In the case of an ItemsControl it will be a ContentPresenter, but a ListBox will return a ListBoxItem, ListView a ListViewItem, etc.

ContentPresenter cp = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as ContentPresenter;
TextBox tb = FindVisualChild<TextBox>(cp);
if (tb != null)
{
    // do something with tb
}

public static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            if (child != null && child is T)
            {
                return (T)child;
            }

            T childItem = FindVisualChild<T>(child);
            if (childItem != null) return childItem;
        }
    }
    return null;
}

You can also obtain the container by index if you want by using

itemsControl.ItemContainerGenerator.ContainerFromIndex(0);

Thanks Bryce, I tried to tick the up arrow but it says my rating is too low! Sorry!

I amended the code to return all a list of all the children of the given type as it was what I needed and thought someone else might find it useful.

Thanks again Bryce, really helpful - sorry about the rating thing!

public static List<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
    {
        List<T> list = new List<T>();
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    list.Add((T)child);
                }

                List<T> childItems = FindVisualChildren<T>(child);
                if (childItems != null && childItems.Count() > 0)
                {
                    foreach (var item in childItems)
                    {
                        list.Add(item);
                    }
                }
            }
        }
        return list;
    }

You may want to try using VisualTreeHelper. The properties on ItemsControl itself will only allow you to get the data its bound to, not the template instances used to visualize the data, while VisualTreeHelper allows you to browse around the visual tree as WPF has rendered it.

If you iterate through the parent ItemControl's visual children (recursively), you shouldn't have any difficulty locating the text boxes you are seeing on screen.

Another example:

    private void DataGridBank_KeyUp(object sender, System.Windows.Input.KeyEventArgs e)
    {
        try
        {     
            switch (e.Key)
            {
                case Key.Down:

                    if ((DataGridBank.SelectedIndex + 1) <= DataGridBank.Items.Count)
                    {
                        DataGridBank.SelectedIndex = DataGridBank.SelectedIndex + 1;
                        FocusCell();
                    }
                    break;

                case Key.Up:

                    if ((DataGridBank.SelectedIndex - 1) >= 0)
                    {
                        DataGridBank.SelectedIndex = DataGridBank.SelectedIndex - 1;
                        FocusCell();
                    }
                    break;

                case Key.Enter:
                case Key.Tab:
                    FocusCell();                   

                    break;
            }
        }
        catch (Exception ex)
        {

        }
    }


    private void DataGridBank_Loaded(object sender, RoutedEventArgs e)
    {
        try
        {
            if (DataGridBank.Items.Count > 0)
            {
                DataGridBank.SelectedIndex = 0;

                FocusCell();
            }

        }catch(Exception ex)
        {

        }
    }


    private void FocusCell()
    {
        var selectedRow = (DataGridRow)DataGridBank.ItemContainerGenerator.ContainerFromItem(DataGridBank.SelectedItem);

        var textImport = FindVisualChild<TextBox>(selectedRow);
        textImport.Focus();
        textImport.SelectAll();
    }


    public static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null && child is T)
                {
                    return (T)child;
                }

                T childItem = FindVisualChild<T>(child);
                if (childItem != null) return childItem;
            }
        }
        return null;
    }
Mohamed Abdo

If you have data grid and template column, which contains data template, you can use the following code sample

<DataGridTemplateColumn x:Name="photoPathColumn" Header="{x:Static resx:FrmResource.Photo}">
    <DataGridTemplateColumn.CellEditingTemplate x:Uid="keyelm">
        <DataTemplate x:Name="dodo">
            <StackPanel Orientation="Horizontal" Height="Auto">
                <TextBlock x:Name="photo" x:Uid="imageFile" Text="{Binding Path=PhotoPath}" />
                <Button x:Name="Browse" Content="..." Click="Browse_Click" />
            </StackPanel>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>

photoPathColumn.CellEditingTemplate.FindName("photo",photoPathColumn.GetCellContent(CustomersDataGrid.CurrentItem)) 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!