简体   繁体   中英

ListBox binding to ObservableCollection<string>

In the following class, the itemssource of a listbox should bind to the Interfaces property.

public class BaseClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private const string TYPE_TITLE = "Type";

    private string  _Type;

    public string Type
    {
        get { return _Type; }
        set { _Type = value; this.NotifyPropertyChanged(PropertyChanged, TYPE_TITLE); }
    }

    public ObservableCollection<string> Interfaces { get; set; }

    public BaseClass()
    {
        Interfaces = new ObservableCollection<string>();
    }

    public void Reset()
    {
        _Type = null;
        Interfaces.Clear();
    }
}

In that list box the selected item should be able to edit as the inline edit scenario,

<DataTemplate x:Key="BaseClass_Interfaces_InlineEdit_Template">
    <TextBox Text="{Binding Mode=TwoWay, Path=., NotifyOnTargetUpdated=True, UpdateSourceTrigger=PropertyChanged}" TextChanged="TextBox_TextChanged"/>
</DataTemplate>
<DataTemplate x:Key="BaseClass_Interfaces_InlineView_Template">
    <TextBlock Text="{Binding Path=., UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>

<Style TargetType="{x:Type ListBoxItem}" x:Key="BaseClass_Iterfaces_ItemStyle_Template">
    <Setter Property="ContentTemplate" Value="{StaticResource BaseClass_Interfaces_InlineView_Template}" />
    <Style.Triggers>
        <Trigger Property="IsSelected" Value="True">
            <Setter Property="ContentTemplate" Value="{StaticResource BaseClass_Interfaces_InlineEdit_Template}" />
        </Trigger>
    </Style.Triggers>
</Style>

The ListBox has a container as a parent hierarchy which its DataContext property bind to an instance of BaseClass hence the ListBox could bind to the Interfaces property.

<ListBox Grid.Row="2" Grid.ColumnSpan="2" Margin="3" ItemsSource="{Binding Interfaces, Mode=TwoWay}" SelectionMode="Single"
             ItemContainerStyle="{StaticResource ResourceKey=BaseClass_Iterfaces_ItemStyle_Template}" />
  • The list box before select any item
    选择任何项目之前的列表框
  • Editing the selected item
    编辑所选项目
  • Another item select after edit and the changes doesn't affected
    编辑后选择已更改

There are two problems :

  1. The TextBox should have "Path=." otherwise the "Two-way binding requires Path or XPath." exception message received.
  2. With consider the above problem, the ObservableCollection items never updated after text changed!!!!!!

I found the answer!
My wondering was about the text box which the text property changed but the changes does not propagated to the source, based on the link the binding mechanism works on the properties of sources in the other words the change of the properties monitors not the object itself.
The solution is a wrapper class around the string, i wrote this wrapper before for another primitive type (bool).

public class Wrapper<T>
{
    public T Item { get; set; }

    public Wrapper(T value = default(T))
    {
        Item = value;
    }

    public static implicit operator Wrapper<T>(T item)
    {
        return new Wrapper<T>(item);
    }

    public static implicit operator T(Wrapper<T> item)
    {
        if (null != item)
            return item.Item;

        return default(T);
    }
}

So the editing data template change as follow

<DataTemplate x:Key="BaseClass_Interfaces_InlineEdit_Template">
    <TextBox Text="{Binding Mode=TwoWay, Path=Item, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>  

And every thing work as charm!!!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM