2
votes

Hey I need to access items in my listbox I've made in WPF. What I have right now is the user can add a new class object to ObservableCollection which the ListBox.ItemsSource is bound to. This class has data in it where that data is used in things like a combobox, a text box and other simple things like that.

What i've made is really based off of one of the tut videos from windowsclient.net

    //Here's What I have so far
    <ListBox x:Name="MyList" Width = "300" Height = 300">
         <ListBox.ItemTemplate>
              <DataTemplate>
                   <StackPanel Orientation="Vertical">
                        <TextBlock x:Name="ItemName" 
                         Text={Binding Path=PersonName}/>
                        <ComboBox x:Name="NumberOfRes" 
                         SelectedIndex="0"
                         SelectionChanged="NumberOfRes_SelectionChanged"
                         ItemsSource={Binding Path=ListOfNums}/>
                   </StackPanel>
              </DataTemplate>
         </ListBox.ItemTemplate>
    </ListBox>

    //ListOfNums
    private ObservableCollection<int> _listofNums = 
                     new ObservableCollection<int>()
    { 1,2,3,4,5,6,7,8 };
    public ObservableCollection<int> ListOfNums
    {
         get{return _listOfNums;}
    }

    //class Resident
    public class Resident
    {
        public string personName {get;set;}
    }

So I have that working. I have a button that adds a new class object and each object has it's data set properly through data binding. So I can see my default personName when a new object is added and I have a comboBox filled with integers from ListOfNums.

My propblem though is that I don't know how to access what these 'sub objects' (forgive me I'm new to WPF and don't know the proper term) are selecting. I want to know what my comboBox's SelectedItem is when a selectionChange event is raised or what my new personName is set to when the user types something into the textBox. So a user selects one of these ItemTemplate objects in the listBox and this item has a combobox and other UI controls that the user clicks. When the user clicks on one of these UI controls some data changes.

I've tried ((Resident)MyList.SelectedItem).personName and a couple other methods just to see if I can access the data and manipulate it. Now the funny thing is that my comboBox in the ItemTemplate has a selection changed event that is called when the selection is changed, but I can't access the data!

Thanks in advance!

2

2 Answers

1
votes

There are multiple ways to accomlish what you are after. The easiest approach would be to put a SelectedItem property on your ViewModel.

Your VieWModel would then look like this...

public class MyViewModel : INotifyPropertyChanged
{
      ObservableCollection<Resident> Residents { get; }

      private Resident _selectedItem;
      public Resident SelectedItem
      {
           get { return _selectedItem; }
           set
           {
                _selectedItem = value;
                PropertyChangedEventHandler handler = PropertyChanged;
                if(handler != null)
                    handler(this, new PropertyChangedEventArgs("SelectedItem");
           }
      }
}

In your View set the DataContext to an instance of this ViewModel, where your ListBox.ItemsSource is bound to Residents and your ListBox.SelectedItem is bound to SelectedItem.

<ListBox ItemsSource="{Binding Path=Residents}" 
         SelectedItem="{Binding Path=Selectedtem, Mode=TwoWay}" />

If you want to perform manipulation when the selection changes, note the setter of your SelectedItem property, which will contain the newly selected item.

EDIT:

Just noticed that your Resident model does not implement INotifyPropertyChanged, which it will need to do to propagate changes down stream. You can then get the point at which the data will change within the setter of a given property as mentioned with the SelectedItem property.

0
votes

Below sample uses a ViewModel (VM). If you add new residents to the Residents collection they will show up in the listbox. Just a tip, if you end up naming your controls a lot you are not doing data binding correctly.

XAML:

<ListBox ItemsSource="{Binding Path=Residents}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Path=PersonName}" />
                <ComboBox 
                    ItemsSource="{Binding Path=DataContext.ListOfNums, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" 
                    SelectionChanged="NumberOfRes_SelectionChanged" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Code behind:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        DataContext = new VM();
    }

    private void NumberOfRes_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
    {
        ComboBox comboBox = sender as ComboBox;
        Resident resident = comboBox.DataContext as Resident;
        int number = (int)comboBox.SelectedItem;
    }
}

public class VM
{
    public VM()
    {
        Residents = new ObservableCollection<Resident>() { new Resident() { PersonName = "AAA" }, new Resident() { PersonName = "BBB" } };
    }

    public ObservableCollection<Resident> Residents { get; private set; }

    public IEnumerable<int> ListOfNums
    {
        get { return new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8 }; }
    }
}

public class Resident
{
    public string PersonName { get; set; }
}