C# – Editable WPF ListBox

cdata-bindingwpf

I have a ObservableCollection that's bound to a ListBox in WPF. I want the ListBox to be editable, and for the editing changes to be saved to the collection. Since WPF doesnt provide an editable listbox, I've tried creating my own by changing the ListBox.ItemTemplate.

<ListBox.ItemTemplate>
    <DataTemplate>                      
        <TextBox Name="EditableText" Text="{TemplateBinding Content}"/>
    </DataTemplate>
</ListBox.ItemTemplate>

Changing the ItemTemplate gives me editable boxes, but any changes to the textboxes dont get saved to the ObservableCollection. Is there a way to have an editable ListBox with two way binding?

Best Answer

You cannot do it this way.

To achieve that kind of trick, you would need your items to be "holder classes" that expose a property you can bind your textbox to.

To understand it, imagine the following pseudo sequence of calls:

class ListBox
{
  Bind(Items)
  {
    foreach(var item in Items)
    {
      DataTemplate Template = LoadTemplateForItem(item.GetType()); // this is where your template get loaded
      Template.Bind(item); //this is where your template gets bound
    }
  }
}

Your template (the DataTemplate with the listbox) is loaded and the item (which I assume is a string in your case) gets passed in. At this point, it only knows the string, and cannot influence anything upwards. A two-way binding cannot influence the collection because the template does not know in which context it is being used, so it cannot reach back to the original collection and modify its contents. For that matter, this is the same thing for the TextBox. If it is not given a conainer and a property name, it has nowhere to "store back" the changes. This basically the same as passing a string into a function call. The function cannot change which string was passed in (ignoring tricks such as by-reference argument passing).

To get back to your case, you need to build a collection of objects which expose a property containing the value that needs to be edited:

public class MyDataItem
{
  string Data { get; set;}
}

Then you can bind your ListBox to a collection of those items and modifiy your datatemplate:

<ListBox.ItemTemplate>
    <DataTemplate>                                              
            <TextBox Name="EditableText" Text="{Binding Data, Mode=TwoWay}"/>
    </DataTemplate>
</ListBox.ItemTemplate>
Related Topic