C# > UI Programming > WPF > MVVM Pattern

WPF MVVM Example: List Binding and Item Selection

This snippet extends the basic MVVM example to demonstrate binding a list of data to a WPF `ListBox` and handling item selection. It showcases how to display a collection of items in the UI and respond to user selection events.

Project Setup

Create a new WPF application project in Visual Studio. This example builds upon the previous example, so you can reuse the same project structure.

Model: Person Class

The Model represents a person with a name and age. This data will be displayed in the ListBox.

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

ViewModel: List and Selection Logic

The `PeopleViewModel` holds an `ObservableCollection` of `Person` objects, which is bound to the `ListBox`. `ObservableCollection` automatically notifies the UI when items are added or removed. The `SelectedPerson` property represents the currently selected item in the `ListBox`. The `SelectedPersonDetails` property displays the details of the selected person and is also updated when the selection changes.

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class PeopleViewModel : INotifyPropertyChanged
{
    private ObservableCollection<Person> _people;
    private Person _selectedPerson;

    public PeopleViewModel()
    {
        _people = new ObservableCollection<Person>
        {
            new Person { Name = "Alice", Age = 30 },
            new Person { Name = "Bob", Age = 25 },
            new Person { Name = "Charlie", Age = 35 }
        };
    }

    public ObservableCollection<Person> People
    {
        get { return _people; }
        set
        {
            _people = value;
            OnPropertyChanged();
        }
    }

    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            _selectedPerson = value;
            OnPropertyChanged();
            OnPropertyChanged(nameof(SelectedPersonDetails));
        }
    }

    public string SelectedPersonDetails
    {
        get
        {
            if (SelectedPerson != null)
            {
                return $"Name: {SelectedPerson.Name}, Age: {SelectedPerson.Age}";
            }
            return "No person selected.";
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

View: XAML Definition

The `ListBox`'s `ItemsSource` property is bound to the `People` property in the ViewModel. The `SelectedItem` property is bound to the `SelectedPerson` property. The `DisplayMemberPath` property specifies which property of the `Person` object to display in the `ListBox` (in this case, the `Name`). The `TextBlock` displays the details of the selected person.

<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <StackPanel>
            <ListBox ItemsSource="{Binding People}" SelectedItem="{Binding SelectedPerson}" Height="200" Margin="10" DisplayMemberPath="Name"/>
            <TextBlock Text="{Binding SelectedPersonDetails}" Margin="10"/>
        </StackPanel>
    </Grid>
</Window>

Code-Behind: Setting the DataContext

The code-behind sets the `DataContext` of the Window to an instance of the `PeopleViewModel`. This is essential for the data binding to work correctly.

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new PeopleViewModel();
    }
}

Concepts Behind the Snippet

This snippet demonstrates how to bind a collection of data to a UI control using MVVM. `ObservableCollection` is essential for automatically updating the UI when the collection changes. Handling item selection allows you to respond to user interactions and display relevant information based on the selected item.

Real-Life Use Case

Consider a list of products in an e-commerce application. The `ListBox` would display the product names, and when the user selects a product, the details of that product (price, description, etc.) would be displayed in another part of the UI. This example can be extended to handle more complex data and UI interactions.

Best Practices

  • Use `ObservableCollection` for collections that need to be automatically updated in the UI.
  • Implement `INotifyPropertyChanged` correctly in your Model and ViewModel classes.
  • Keep the ViewModel focused on data and logic, and avoid directly manipulating UI elements.
  • Use data binding to connect the View and ViewModel.

Interview Tip

Be prepared to explain the difference between `List` and `ObservableCollection` in the context of data binding. Also, understand how item selection is handled in MVVM and how to display details of the selected item. Be ready to discuss the benefits of using collections.

When to Use Them

Use this pattern when you need to display a list of data in the UI and respond to user selection events. It's particularly useful for applications with a large amount of data and complex UI interactions.

Memory Footprint

`ObservableCollection` can potentially increase memory usage compared to a regular `List` because it needs to track changes and notify the UI. However, the benefits of automatic UI updates usually outweigh this consideration. Be mindful of the size of the collection and consider using virtualization if you are displaying a very large number of items.

Alternatives

Alternatives to using `ListBox` include `ListView` and `DataGrid`, which offer more advanced features for displaying data. You can also use custom controls to create a more tailored UI experience. The choice depends on the specific requirements of your application.

Pros

  • Simplified data binding for collections
  • Automatic UI updates when the collection changes
  • Clear separation of concerns
  • Easy to handle item selection

Cons

  • Increased memory usage compared to regular lists
  • Requires careful implementation of `INotifyPropertyChanged`
  • Can be more complex than simpler approaches for very basic lists

FAQ

  • What is the difference between `List` and `ObservableCollection`?

    The main difference is that `ObservableCollection` implements the `INotifyCollectionChanged` interface, which allows it to notify the UI when the collection changes (e.g., items are added, removed, or replaced). A regular `List` does not provide this notification mechanism, so the UI will not automatically update when the list changes.
  • How do I handle item selection in a `DataGrid` using MVVM?

    You can bind the `SelectedItem` property of the `DataGrid` to a property in your ViewModel, similar to the `ListBox` example. When the user selects a row in the `DataGrid`, the `SelectedItem` property in the ViewModel will be updated. You can then respond to this change and perform any necessary actions.
  • How can I improve performance when displaying a large number of items in a `ListBox` or `DataGrid`?

    Consider using UI virtualization, which only renders the visible items in the list. This can significantly improve performance when displaying a large number of items. Also, use efficient data binding techniques and avoid unnecessary UI updates.