Search code examples
wpflistview2-way-object-databinding

How do I bind a Listview SelectedItem to a Textbox using the TwoWay mode?


I am very new to WPF and testing some things that I would like to include in an application that I will be working on. I have a 2 row ListView (bound to a textbox) with the names Scott Guthrie and Jon Skeet in it. I am trying to select "Scott Guthrie" in the ListView and have it populate the TextBox. I want to be able to edit the text and tab off and have the ListView updated.

Edit:I removed the code since that really didn't add anything to the question.


Solution

  • Wow, that's really complicated what you've got there.

    This can be accomplished in a very simple way. You need a model to represent the programmer, a view model to hold a list of programmers, and simple binding to take care of the rest.

    The model:

    public sealed class Programmer
    {
        public string Name { get; set; }
    }
    

    Its very simple. An object representing a programmer with a name. We must encapsulate the name within an object because strings are immutable in .NET. If you tried binding against a single string in a list of strings, changes wouldn't propagate.

    The collection of programmers is kept in a ViewModel. In this case, I call it ViewModel, because I have no imagination. This view model contains everything that the view binds against. In this case, its the list of programmers.

    public sealed class ViewModel
    {
        public ObservableCollection<Programmer> Programmers { get; private set; }
    
        public ViewModel()
        {
            Programmers = new ObservableCollection<Programmer>();
        }
    }
    

    The ViewModel is set as the DataContext of our view. The DataContext flows down the visual tree, and we can bind against it at any point.

    public MainWindow()
    {
        var vm = new ViewModel();
        vm.Programmers.Add(new Programmer { Name = "Jon Skeet" });
        vm.Programmers.Add(new Programmer { Name = "Scott Guthrie" });
        DataContext = vm;
        InitializeComponent();
    }
    

    You can set the DataContext in any way you want; I'm doing it here for simplicity's sake.

    In the UI, I simply bind the ListView against the list of Programmers in the ViewModel (the DataContext, unless otherwise stated, is the root of the binding path). I then bind the TextBox against the SelectedItem of the ListBox. You select a Programmer from the list, which then becomes the SelectedItem, which I can then change the Name of.

    <Window
        x:Class="Programmers.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:t="clr-namespace:Programmers"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <ListBox
                x:Name="list"
                ItemsSource="{Binding Programmers}"
                DisplayMemberPath="Name" />
            <TextBox
                Grid.Column="1"
                VerticalAlignment="Top"
                Text="{Binding SelectedItem.Name, ElementName=list}" />
        </Grid>
    </Window>
    

    Simple, once you get the hang of it.