开发者

Binding current context of ICollection<T> in ListView to combo box

开发者 https://www.devze.com 2023-02-23 14:52 出处:网络
Background I need to allow users to edit an IList<Move> moves where Move is an immutable class.Users choose moves from a drop-down (ComboBox).For example:

Background

I need to allow users to edit an IList<Move> moves where Move is an immutable class. Users choose moves from a drop-down (ComboBox). For example:

[[ for every move slot ]]
    <ComboBox DisplayMemberPath="Name" ItemsSource="{DynamicResource MoveCollection}" SelectedValue="[[ move of the move slot ]]" />
[[ end for ]]

My approach

I am using a ListView to iterate over the collection, and a DataTemplate to create the ComboBox instances, as follows:

<ListView ItemsSource="{Binding Moves}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ComboBox DisplayMemberPath="Name" ItemsSource="{DynamicResource MoveCollection}" SelectedValue="{Binding}" />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

I get an exception with this ("Two-way binding requires Path or XPath."), so I resorted to the following binding expression for SelectedValue:

{Binding Path=DataContext, RelativeSource={RelativeSource Self}}

This makes it compile and run. However, the moves collection is not updated as the user makes changes. Obviously, only the data context is being changed, not the actual value.

I believe this is an issue because the IList<Move> is simply treated as a read-only collection by WPF, and changes to the combo box's value do not and cannot modi开发者_如何学运维fy that collection. In code, WPF cannot do the following:

moves[x] = Resources["MoveCollection"][y];

I would like for changes in the combo box's value to update the moves collection. How can I accomplish this?


Yes, your suspicions about IList are partially correct. Let's take a look at what's actually happening under the hood: ListView is handed a collection of items. For each item, it creates a new copy of the data template within a panel specified by the panel template. The data template is going to be handed a reference to the object it's interested in as its DataContext. So even if you changed the value successfully, the underlying scenario looks like this in C#:

List yourItems = ...; foreach(string yourItem in yourItems) { someControl.DataContext = yourItem;

//you change it here someControl.DataContext = yourNewItem; }

You wouldn't expect the above code to change the list. Although it's a bit different, I think what's going on here is similar.

I believe the simplest way to do what you're trying to do would be to make an IList>. Wrapper would just be a dummy class wrapping a Move. Binding would then change the Move on the Wrapper. On the backend, it'll be trivial to unwrap the list when you need it with a little LINQ.

How's that sound?

0

精彩评论

暂无评论...
验证码 换一张
取 消