I'm having problems finding a control (ToggleSwitch) inside my ListView. I have tried several approaches found here on SO or on other places around the web but none seems to be working.

Here is a the listView markup

<ListView Name="LampsListView" ItemsSource="{x:Bind Lamps}">
    <ListView.ItemTemplate>
        <DataTemplate x:DataType="models:Lamp">
            <StackPanel Name="StackPanel">
                <TextBlock Margin="10,0" Text="{Binding Name}" VerticalAlignment="Center" HorizontalAlignment="Left" />
                <ToggleSwitch Margin="10,0" HorizontalAlignment="Right" Name="LampToggleSwitch" IsOn="{x:Bind State, Converter={ StaticResource IntToIsOn}}" />
            </StackPanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

I have tried the ContainerFromItem but x will always be null.

 foreach (var item in this.LampsListView.Items)
 {
     var x = this.LampsListView.ContainerFromItem(item);
 }

And also the GetChildren approach but even thought GetChildren returns items it wont give me anything I can work with.

 private void FindMyStuff()
 {
     var ch = this.GetChildren(this.LampsListView);
 }

 private List<FrameworkElement> GetChildren(DependencyObject parent)
 {
     List<FrameworkElement> controls = new List<FrameworkElement>();

     for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); ++i)
     {
         var child = VisualTreeHelper.GetChild(parent, i);
         if (child is FrameworkElement)
         {
             controls.Add(child as FrameworkElement);
         }
         controls.AddRange(this.GetChildren(child));
     }
     return controls;
}

And I've tried booth finding the StackPanel and go straight for the LampToggleSwitch.

The FindMyStuff() is called right after i've updated the ObservableCollection that is bound to the ListView and the update is done from a this.Dispatcher.RunAsync(). I don't know if this has anything to do with it thought.

Could someone please tell me what I'm doing wrong?

Generally traversing visual tree or getting items by names/types is in most cases a wrong way of doing thigs, much better would be to implement apropriate binding.

Nevertheless if you want to do this, you are almost there. As I've tried it should work like this:

var listViewItem = this.mylist.ContainerFromItem(mylist.Items.First()) as ListViewItem;
var itemsStackPanel = listViewItem.ContentTemplateRoot as StackPanel;
var myToggleSwitch = itemsStackPanel.Children.FirstOrDefault(x => x is ToggleSwitch);
// other way with your helper
var childByHelper = GetChildren(listViewItem).FirstOrDefault(x => x is ToggleSwitch);

Just watch out when you run this, if it's done before list is populated, listVieItems will be null.


+ Recent posts