[WPF] BindingListCollectionView ignores item replace
- Dominant language
- C#
- Stars
- 7.7k
- Forks
- 1.3k
- Avg merge
- 1d 11h
- Merged PRs (30d)
- 61
Description
Disclaimer: I know that ObservableCollection<T> is the recommended collection type for bindings. Still, if a collection implements both INotifyCollectionChanged and IBindingList interfaces (such as ObservableBindingList<T>), then WPF prefers to handle it as a binding list (picks a BindingListCollectionView for it), which has the issues described below.
Issue Reproduction Steps:
- Bind a DataGrid to a BindingList<T> where T implements INotifyPropertyChanged. You can use this demo app. Just select BindingList and ObservableTestObject as list and element types, respectively.
- Replace an element in the bound list. In the linked app press the Item button on the toolbar to do so.
- As a result, the item will be replaced but the controls will not get any notification. By pressing Item again, an error occurs because a non-existing item is tried to be replaced.
Remark: If T does not implement INotifyPropertyChanged (select PlainTestObject in the app linked above), then replace works; however, since a Reset change type is raised instead of Replace the selection always jumps to the first item.
Proposed fix:
After analyzing the BindingListCollectionView source it seems that the issue can be fixed by a small change in the OnListChanged method:
case ListChangedType.ItemChanged:
////// Fix starts here - here ItemChanged refers to a Replace event (indexer set) and not a property change
if (args.PropertyDescriptor == null)
{
item = InternalList[index];
var oldItem = _cachedList[index];
_cachedList[index] = item;
forwardedArgs = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem, index);
break;
}
////// Fix ends here - below is the original code where ItemChange refers to a property changeif (!_itemsRaisePropertyChanged.HasValue)
{
// check whether individual items raise PropertyChanged events
// (DataRowView does)
item = InternalList[args.NewIndex];
_itemsRaisePropertyChanged = (item is INotifyPropertyChanged);
}// if items raise PropertyChanged, we can ignore ItemChanged;
// otherwise, treat it like a Reset
if (!_itemsRaisePropertyChanged.Value)
{
goto case ListChangedType.Reset;
}
break;
Disclaimer: I could not test it.
_This issue has been moved from https://developercommunity.visualstudio.com/content/problem/651699/wpf-bindinglistcollectionview-ignores-item-replace.html
VSTS ticketId: 949137_
_These are the original issue comments:_
Visual Studio Feedback System on 7/19/2019, 02:18 PM (35 min ago):
We have directed your feedback to the appropriate engineering team for further evaluation. The team will review the feedback and notify you about the next steps.
_These are the original issue solutions:_
(no solutions)
Contributor guide
Assessment
This issue has not been assessed yet.