none
Bind To ListBox's SelectedItems

    Question

  • Hey,

    Is there any way that I can bind a list (or any other collection) to a listbox's SelectedItems property?

    Basically, I have a query screen.  All of the controls on the query screen are bound to properties on an underlying data model object.  The only control that is giving me trouble is the list box.  I'd like to have a list of the currently selected items in the list box maintained in my data model through binding.  Is this possible?  Going further: if the items in my list box are Person instances where the Person class has a SSN property, could I bind a list of SSN to the SelectedItems property?

    Thanks
    Thursday, June 12, 2008 6:55 PM

Answers

  • I believe (I've only read this, never tried it) that you can bind from a WPF control back to an object by using the binding mode OneWayToSource.  It basically reverses the binding direction. 

    As far as binding to a specific property, I believe you can do this in one of two ways.

    If you bind a ListBox (or any ItemsContainer) to a list of objects, you can place controls within the item that just display a particular property.  For instance, if you have an ItemTemplate for your ListBox, you can put a TextBlock in your DataTemplate with the following attribute : Text={Binding Path=SSN} or I believe you can even use DisplayMemberPath="SSN" (both assume that SSN is defined as a property of your Person object...I had a problem in the past trying to bind to a simple public field until I realized it had to be specifically implemented as a public property with a get{}).  Remember that when you use an ItemTemplate, {Binding} now refers to the item in the collection that you are binding to.  You can use {Binding Path=...} to get anything you want out of the object.

    You can also derive People from List<Person> and create a property of the People class named SSNumbers of type List<string> (that iterates the list of Person objects and adds the SSN of the person to SSNumbers).  You can then bind a list control to People.SSNumbers.

    For example:
     
     
        public class Person 
        { 
            private string ssn = ""
            public string SSN 
            { 
                get { return ssn; } 
            } 
        } 
     
        public class People : List<Person> 
        { 
            private List<string> ssNumbers = null
            public List<string> SSNumbers 
            { 
                get 
                { 
                    if (ssNumbers == null
                    { 
                        foreach (Person p in this
                        { 
                            ssNumbers.Add(p.SSN); 
                        } 
                    } 
                    return ssNumbers; 
                } 
            } 
        } 
    • Marked as answer by Marco Zhou Thursday, June 19, 2008 10:01 AM
    Friday, June 13, 2008 3:37 PM

All replies

  • I don't think you can bind directly to SelectedItems property of a listbox; however, you can cast SelectedItems into INotifyCollectionChanged, and listen to the CollectionChanged event. Then, in the event handler, you can do whatever you need, such as getting a list of SSNs from all selected Persons...
    Friday, June 13, 2008 2:02 AM
  • I believe (I've only read this, never tried it) that you can bind from a WPF control back to an object by using the binding mode OneWayToSource.  It basically reverses the binding direction. 

    As far as binding to a specific property, I believe you can do this in one of two ways.

    If you bind a ListBox (or any ItemsContainer) to a list of objects, you can place controls within the item that just display a particular property.  For instance, if you have an ItemTemplate for your ListBox, you can put a TextBlock in your DataTemplate with the following attribute : Text={Binding Path=SSN} or I believe you can even use DisplayMemberPath="SSN" (both assume that SSN is defined as a property of your Person object...I had a problem in the past trying to bind to a simple public field until I realized it had to be specifically implemented as a public property with a get{}).  Remember that when you use an ItemTemplate, {Binding} now refers to the item in the collection that you are binding to.  You can use {Binding Path=...} to get anything you want out of the object.

    You can also derive People from List<Person> and create a property of the People class named SSNumbers of type List<string> (that iterates the list of Person objects and adds the SSN of the person to SSNumbers).  You can then bind a list control to People.SSNumbers.

    For example:
     
     
        public class Person 
        { 
            private string ssn = ""
            public string SSN 
            { 
                get { return ssn; } 
            } 
        } 
     
        public class People : List<Person> 
        { 
            private List<string> ssNumbers = null
            public List<string> SSNumbers 
            { 
                get 
                { 
                    if (ssNumbers == null
                    { 
                        foreach (Person p in this
                        { 
                            ssNumbers.Add(p.SSN); 
                        } 
                    } 
                    return ssNumbers; 
                } 
            } 
        } 
    • Marked as answer by Marco Zhou Thursday, June 19, 2008 10:01 AM
    Friday, June 13, 2008 3:37 PM
  • Hi,

    I ran into this problem, and I wanted the multi-selection to work in both directions. That is, I wanted the user to be able to multi-select items and be aware of what items are selected in my model. I also wanted my model to be able to clear the user selection when some external event dictated this was the logical thing to do. In my case the, above solution won't work.

    My workaround was as follow: In my case, I had my ListBox.ItemsSource bound to an ObsvervableCollection of Action objects. In my Action class, I have a bool property IsSelected that let's each Action be responsible for knowing if it's selected or not:

    public class Action : INotifyPropertyChanged  
       public bool IsSelected 
       { 
          get 
          { 
             return _isSelected; 
          } 
          set 
          { 
             _isSelected = value; 
             if (PropertyChanged != null
             { 
                PropertyChanged(thisnew PropertyChangedEventArgs("IsSelected")); 
             } 
          } 
       } 
     
       public event PropertyChangedEventHandler PropertyChanged; 
     
       //...rest of code for Action here...// 

    In my ListBox, I set the ItemContainerStyle to bind ListBoxItem.IsSlected to Action.IsSelected:

    <ListBox ItemsSource="{Binding Actions}" 
             SelectionMode="Multiple"
       <ListBox.ItemContainerStyle> 
          <Style TargetType="{x:Type ListBoxItem}"
             <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/> 
          </Style> 
       </ListBox.ItemContainerStyle> 
    </ListBox> 
     

    Then this just automagically works. It's pretty simple, but not so simple to know this is how to do it. I hope this helps someone else out.

    Cheers,
    Adam Cataldo


    Friday, December 12, 2008 10:59 PM