Using VisualTreeHelper on listbox, can't get l

2019-01-28 08:39发布

问题:

I have the following XAML:

 <ListBox HorizontalAlignment="Left" Margin="0,6,0,10" Name="listBox1" Width="468" ItemsSource="{Binding}" Grid.ColumnSpan="1">
  <ItemsControl.ItemTemplate>
   <DataTemplate>
    <StackPanel Orientation="Horizontal">
     <TextBox Name="txt1" Text="{Binding Propty1}" IsEnabled="False"></TextBox>
     <CheckBox IsChecked="{Binding Propty2}" Name="{Binding Propty2}" Click="chk_Clicked"></CheckBox>
     <TextBox Text="{Binding Propty2}" Name="{Binding Propty3}" GotFocus="txt_GotFocus" LostFocus="txt_OnLostFocus" KeyDown="txt_OnKeyDown"/>
   </StackPanel>
  </DataTemplate>
 </ItemsControl.ItemTemplate>
</ListBox>

After an event happens (a button outside of listbox is clicked, then the data in the listbox is reloaded), I need to focus on one of the textboxes in the listbox. I use VisualTreeHelper to go through the listbox. Here is the code:

    void SetFocusOnTextBox(DependencyObject element)
    {
        ListBoxItem listItem = element as ListBoxItem;
        if (listItem != null)
        {
            //find textbox and set focus here
        }

        int children = VisualTreeHelper.GetChildrenCount(element);
        for (int i = 0; i < children; i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(element, i);
            SetFocusOnTextBox(child);
        }
    }

However, I don't get any items of type listbox when I call the method in the following line of code:

           SetFocusOnTextBox(listBox1);

I get ListBox, ScrollViewer, Border, Grid, ContentPresenter, ItemsPresenter, VirtualizingStackPanel and so on, but no listboxitems. What am I doing wrong? How do I find listboxitems (and then textboxes) in the listbox? Thank you.

回答1:

Silverlight is Asynchronous!

...the data in the listbox is reloaded...

When you change DataContext with some new data it doesn't mean that actual data will be loaded immediately. Just before you trying to get ListboxItem just simply call listBox1.UpdateLayout and everything should be fine.

public partial class MainPage : UserControl
{
    public MainPage()
    {
        InitializeComponent();

        Loaded += new RoutedEventHandler(MainPage_Loaded);
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        ReloadData();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        // 1 - Uncomment this line to crush your app
        // ReloadData();

        // 2 - Uncomment this line to fix everything
        // listBox1.UpdateLayout();

        // UpdateLayout - ensures that actual data is loaded to UI,             
        // all items are created and rendered 

        GetItemsRecursive(listBox1);
    }

    private void GetItemsRecursive(DependencyObject lb)
    {
        var childrenCount = VisualTreeHelper.GetChildrenCount(lb);

        for (int i = 0; i < childrenCount; i++)
        {
            var child = VisualTreeHelper.GetChild(lb, i);


            if (child is ListBoxItem)
            {
                MessageBox.Show(child.GetType().ToString());
                return;
            }

            GetItemsRecursive(child);
        }
    }

    private void ReloadData()
    {
        listBox1.DataContext = new List<Classs>() {
            new Classs{ Propty1 = "sasda", Propty2 = false, Propty3 = "asdasda"},
            new Classs{ Propty1 = "sasda", Propty2 = true, Propty3 = "asdasda"},
            new Classs{ Propty1 = "sasda", Propty2 = false, Propty3 = "asdasda"}
        };
    }
}

public class Classs
{
    public string Propty1 { get; set; }

    public bool Propty2 { get; set; }

    public string Propty3 { get; set; }
}


回答2:

Please try this code snipped below to get the TextBox in ListBoxItem.

ListBox listbox = element as ListBox;
if (listbox != null && listbox.SelectedItem !=null)
{             
//find textbox and set focus here 

Textbox thisTextBox = (listbox.SelectedItem).Find("txt1") as Textbox;
if(thisTextBox !=null)
{
    thisTextBox.Focus();
    return;
}

}
int children = VisualTreeHelper.GetChildrenCount(element);         
for (int i = 0; i < children; i++)         
{
     DependencyObject child = VisualTreeHelper.GetChild(element, i);
     SetFocusOnTextBox(child);         
}