Dwight
Dwight

Reputation: 12460

Proper way to use ListBox (with ItemTemplate) when using a List<>

I've been trying to use a List<> of a Model.Person that I have inside a ListBox, using a ItemTemplate for style and then retrieving the correct Model.Person from the list when one has been selected. I've looked everywhere for sample code (and tried leading data binding, but still can't get my head around it properly).

List<Model.Person> people = (comes from IsolatedStorageSettings)

On a page I have a ListBox, say named "List".

<ListBox Name="List"></ListBox>

In my C# code, I pull a List from the isolated storage. What I want to do ideally is have all the people in that list appear in the ListBox in a nice formatted way, and then when one is selected, easily retrieve the Person from the List<>. What I am doing at the moment, and what is surely wrong is:

foreach (Model.Person person in people)
{
    List.Items.Add(person.firstName + " " + person.lastName);
}

Then, when an item is selected, I find the person using this method:

string selectedPerson = List.SelectedItem.ToString();
Model.Person person = people.Where(X => X.firstName + " " + X.lastName == selectedPerson).FirstOrDefault();

Obviously, the lists in the item just appear as the plain text and not interesting objects as one might create using ItemTemplate. Could someone please show me what I'm doing wrong or point me in the direction of a good resource for achieving this?

Thanks so much!

Upvotes: 1

Views: 599

Answers (2)

MBen
MBen

Reputation: 3996

I would also recommend using ObservableCollection<Person> instead of List<Person>. List doesn't have a built in notification mechanism as does ObservableCollection.

Upvotes: 1

Philip Daubmeier
Philip Daubmeier

Reputation: 14934

You really want to do view related stuff in the view, not in the code behind. Therefore, do not populate the list by hand with code, but instead bind it in the view. The XAML could look something like this:

<ListBox ItemsSource="{Binding Path=People}" SelectedItem="{Binding Path=SelectedPerson, Mode=TwoWay}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=FirstName}" />
                <TextBlock Text="{Binding Path=LastName}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Use a clear structured ViewModel for your page, with a member People and one for the selected Person. It would look something like:

public class YourPageViewModel : INotifyPropertyChanged
{
    public List<Model.Person> People { get; set; }

    private Model.Person _selectedPerson;
    public Model.Person SelectedPerson
    {
        get
        {
            return _selectedPerson;
        }
        set
        {
            if (_selectedPerson != value)
            {
                _selectedPerson = value;
                PropertyChangedEventHandler handler = this.PropertyChanged;
                if (handler != null)
                    handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

Then set the viewmodel in the code behind of the view:

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

        this.Loaded += (s, e) =>
        {
            if (DataContext == null)
                DataContext = new YourPageViewModel();
        };
    }
}

Et voila, you are using a MVVM approach, instead populating the view from the code behind.

Also, I recommend not abusing IsolatedStorageSettings for storing actual data for the app. Use a serializer for your model objects, or take the SQL compact database for Windows Phone to do that.

Upvotes: 3

Related Questions