具有ListView SelectedItem的属性和TextBox绑定的ArgumentException [英] ArgumentException with ListView SelectedItem's property and TextBox binding

查看:81
本文介绍了具有ListView SelectedItem的属性和TextBox绑定的ArgumentException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:

我发现此问题的根源是 Equals() GetHashCode() Bar 中的实现。

I figured out that the source of this problem is the Equals() and GetHashCode() implementation in Bar.

特别是属性(例如 Bar 中的 Name )它参与 GetHashCode(),并且还绑定到 TextBox 。在删除这些覆盖方法时,一切正常(除了我想保留它们)

Especially the properties (like Name in Bar) which participates in GetHashCode() and is also binded to a TextBox. On removing these override methods everything just works fine (except that I want to keep them)

我不明白为什么会这样?

What I don't understand is WHY is this happening??

我有一个 TextBox ,一个 ListView ,以及使用以下ViewModel进行的某些数据绑定:

I have a TextBox, a ListView, and some data bindings with following ViewModel:

[PropertyChanged.ImplementPropertyChanged]
public class ViewModel
{
    public ObservableCollection<Foo> Foos { get; set; }

    public Foo SelectedFoo { get; set; }
}

[PropertyChanged.ImplementPropertyChanged]
public class Foo
{
    public Bar FooBar { get; set; }
}

[PropertyChanged.ImplementPropertyChanged]
public class Bar
{
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        var other = obj as Bar;

        if (other != null)
        {
            return other.Name == Name;
        }

        return false;
    }

    public override int GetHashCode()
    {
        return Name.GetHashCode();
    }
}

这是我的列表:

<ListView x:Name="V_List" SelectedItem="{Binding SelectedFoo}"  ItemsSource="{Binding Path=Foos}" SelectionMode="Single">
    ...
</ListView>

这是我的文本框:

<TextBox Text="{Binding Path=SelectedFoo.FooBar.Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" />

事情就是这样:

何时我从 List 列表中选择第一个 Foo ,绑定起作用,并且 Name Foo FooBar 属性的c $ c>出现在 TextBox 。无论我更改选择多少次,相应的值都会出现在 TextBox 中。

When I select the first Foo from the List, the binding works, and Name of the FooBar property of selected Foo appears in the TextBox. No matter how many times I change my selection, the appropriate value appears in the TextBox.

但是现在如果我使用 TextBox 更改 Name (由于TwoWay数据绑定,在失去焦点后,它正在工作,我检查了(通过调试)),然后从列表中更改我的选择,文本框仍显示先前选择的项目的值。

But now if I change the Name using the TextBox (which, after focus lost, because of TwoWay data binding, is working and I checked with Debugging) and then change my selection from the list, the TextBox still shows the previously selected item's value.

而且,再次选择相同的项目,然后再选择其他一些项目时,我得到以下异常(令人惊讶的是,调试器没有报告,我不得不将其记录到文件中。可能是因为异常不是由我的代码。)

Moreover, upon selecting that same item again, and then selecting some other item, I get the following exception (which surprisingly, the debugger didn't report, I had to log it to a file. Probably maybe because the exception was not raised from my code.)

以下是日志:


例外是:-异常:: System.ArgumentException:已经添加了具有
相同键的项。
处System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
处System.Collections.Generic.Dictionary 2.Insert(TKey键,TValue
值,布尔值添加)
System.Collections.Generic.Dictionary
2..ctor(IDictionary 2
字典,IEqualityComparer
1比较器)为
System.Windows.Controls.Primitives.Selector.InternalSelectedItemsStorage..ctor(InternalSelectedItemsStorage
collection,IEqualityComparer`1 equalityComparer)at
System.Windows.Controls.Primitives.Selector.SelectionChanger.ApplyCanSelectMultiple() System.Windows.Controls.Primitives.Selector.SelectionChanger.End()中的

中的
System.Windows.Controls.Primitives.Selector.SetSelectedHelper(Object
item,FrameworkElement UI ,则在
System.Windows处
System.Windows.Controls.Primitives.Selector.NotifyIsSelectedChanged(Framework Element
容器,已选择布尔值,RoutedEventArgs e)中。 Controls.Primitives.Selector.OnSelected(对象发送者,
RoutedEventArgs e)在
System.Windows.RoutedEventHandlerInfo.InvokeHandler(对象目标,
RoutedEventArgs routedEventArgs)在
System.Windows中。 EventRoute.InvokeHandlersImpl(对象来源,
RoutedEventArgs args,布尔值重新引发)在
System.Windows.UIElement.RaiseEventImpl(DependencyObject sender,
RoutedEventArgs args)在
System.Windows.UIElement .raiseEvent(RoutedEventArgs e)在
处System.Windows.Controls.ListBoxItem.OnSelected(RoutedEventArgs e)


System.Windows.Controls.ListBoxItem.OnIsSelectedChanged(DependencyObject
d,DependencyPropertyChangedEventArgs e)在
上System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs
e)在
System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs
e)在
系统上Windows.DependencyObject.NotifyPropertyChange(D ependencyPropertyChangedEventArgs
args)at
System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex
entryIndex,DependencyProperty dp,PropertyMetadata元数据,
EffectiveValueEntry oldEntry,EffectiveValueEntry& newEntry,布尔值
coerceWithDeferredReference,布尔值coerceWithCurrentValue,
OperationType operationType)位于
System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp,
对象值,PropertyMetadata元数据,布尔值
coerceWithDeferredReference,布尔值coerceWithCurrentValue,
OperationType操作类型,布尔值isInternal在
处System.Windows.DependencyObject.SetCurrentValueInternal(DependencyProperty
dp,对象值)在
处System.Windows.Controls.ListBox .NotifyListItemClicked(ListBoxItem
item,MouseButton mouseButton)在
System.Windows.Controls.ListBoxItem.HandleMouseButtonDown(MouseButton
mouseButton)在
System.Windows.Controls.ListBoxItem.OnMouseLeftButtonDown( System.Windows.UIElement.OnMouseLeftButtonDownThunk(Object
sender,MouseButtonEventArgs e)在
处的MouseButtonEventArgs
e)System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(De在
处的遗留
genericHandler,对象genericTarget)System.Windows.RoutedEventArgs.InvokeHandler(委托处理程序,对象
目标)在
处System.Windows.RoutedEventHandlerInfo.InvokeHandler(对象目标,$
处的b $ b RoutedEventArgs routedEventArgs)System.Windows.EventRoute.InvokeHandlersImpl(Object source,
RoutedEventArgs args,Boolean reRaised)at
System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender,
RoutedEventArgs args,RoutedEvent newEvent)
System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate $ b $)System.Windows.UIElement.OnMouseDownThunk(Object sender,
MouseButtonEventArgs e)at

处的b genericHandler,对象genericTarget)System.Windows.RoutedEventArgs.InvokeHandler(在
处的代理处理程序,对象
目标)System.Windows.RoutedEventHandlerInfo.InvokeHandler(对象目标,
RoutedEventArgs
System.Windows.EventR中的routedEventArgs) oute.InvokeHandlersImpl(对象来源,
RoutedEventArgs args,布尔值重新引发)在
System.Windows.UIElement.RaiseEventImpl(DependencyObject sender,
RoutedEventArgs args)在
System.Windows.UIElement
处的.RaiseTrustedEvent(RoutedEventArgs args)System.Windows.Input.InputManager.ProcessStagingArea()
处的System.Windows.UI.UIElement.RaiseEvent(RoutedEventArgs args,布尔值
受信任)
处的Input.InputManager.ProcessInput(InputEventArgs
输入)System.Windows.Input.InputProviderSite.ReportInput(InputReport
inputReport)在
处System.Windows.Interop.HwndMouseInputProvider.ReportInput( IntPtr hwnd,
InputMode模式,Int32时间戳,RawMouseActions操作,Int32 x,
Int32 y,Int32滚轮)位于
System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr
hwnd ,WindowMessage msg,IntPtr wParam,IntPtr lParam,Boolean&
处理过的
)System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd,
Int32 msg,IntPtr wParam,IntPtr lParam,布尔值和处理)在
MS.Win32。 HwndWrapper.WndProc(IntPtr hwnd,Int32 msg,IntPtr wParam,
IntPtr lParam,布尔值和已处理)at
MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)at
System.Windows.Threading .ExceptionWrapper.InternalRealCall(在
处委托
回调,对象args,Int32 numArgs)System.Windows.Threading.ExceptionWrapper.TryCatchWhen(对象源,
委托回调,对象args,Int32 numArgs,委托catchHandler)

The Exception is:-Exception :: System.ArgumentException: An item with the same key has already been added. at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary2..ctor(IDictionary2 dictionary, IEqualityComparer1 comparer) at System.Windows.Controls.Primitives.Selector.InternalSelectedItemsStorage..ctor(InternalSelectedItemsStorage collection, IEqualityComparer`1 equalityComparer) at System.Windows.Controls.Primitives.Selector.SelectionChanger.ApplyCanSelectMultiple() at System.Windows.Controls.Primitives.Selector.SelectionChanger.End() at System.Windows.Controls.Primitives.Selector.SetSelectedHelper(Object item, FrameworkElement UI, Boolean selected) at System.Windows.Controls.Primitives.Selector.NotifyIsSelectedChanged(FrameworkElement container, Boolean selected, RoutedEventArgs e) at System.Windows.Controls.Primitives.Selector.OnSelected(Object sender, RoutedEventArgs e) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e) at System.Windows.Controls.ListBoxItem.OnSelected(RoutedEventArgs e)
at System.Windows.Controls.ListBoxItem.OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e) at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e) at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args) at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType) at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal) at System.Windows.DependencyObject.SetCurrentValueInternal(DependencyProperty dp, Object value) at System.Windows.Controls.ListBox.NotifyListItemClicked(ListBoxItem item, MouseButton mouseButton) at System.Windows.Controls.ListBoxItem.HandleMouseButtonDown(MouseButton mouseButton) at System.Windows.Controls.ListBoxItem.OnMouseLeftButtonDown(MouseButtonEventArgs e) at System.Windows.UIElement.OnMouseLeftButtonDownThunk(Object sender, MouseButtonEventArgs e) at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent) at System.Windows.UIElement.OnMouseDownThunk(Object sender, MouseButtonEventArgs e) at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget) at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args) at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted) at System.Windows.Input.InputManager.ProcessStagingArea() at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input) at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport) at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel) at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

值得一提的是,我设置 SelectionMode不会引发异常 ListView Multiple 。在这种情况下,列表中的项目其 FooBar 的值我从 TextBox更改了保持选中状态,然后再选择其他任何项。

Another thing worth mentioning that I noticed is, the exception is not raised if I set the SelectionMode of ListView to Multiple. In that case, the item in List whose FooBar's value I changed from the TextBox, remains selected, along with any other items that I may select then after.

注意:我使用的是 Fody / PropertyChanged 来实现 INotifyCollectionChanged

Note: I am using Fody/PropertyChanged to implement INotifyCollectionChanged.

推荐答案


我不明白为什么会这样?

What I don't understand is WHY is this happening?

我不能给您确切的答案,但是看着错误,看起来ListView保留了控件项的内部Dictionary。此外,我敢打赌该内部字典的键是基于GetHashCode的值的。问题是您允许用户更改该键(通过更改name属性),而对象仍是控件的一部分。我猜想,在选择更改时,它会通过添加和删除必要项来维护字典。由于您的商品的有效键已更改,因此它可能试图将其读入内部字典,只是发现该商品已在字典中(但在原始键之下)。

I can't give you a definitive answer, but looking at the error, it looks like the ListView is keeping an internal Dictionary of the control's items. Further, I'd bet the key for that internal dictionary is based on the value of GetHashCode. The problem is that you are allowing your users to change that key (by changing the name property) while the object is still part of the control. I'd guess that on selection changing it's maintaining the dictionary by adding and removing items as necessary. Since the effective "key" for your item has changed, it may be trying to readd it to the internal dictionary, only to find that the item is already in the dictionary (but under the original key).

您可以通过在名称更改时删除更改的项并将其读入Foos集合来检验该理论。那应该用正确的新密钥清除并重新插入内部字典中的项目。

You can test that theory by removing and readding the changed item to the Foos collection when the name changes. That should clear and reinsert the item in the internal dictionary with the correct, new key.

这篇关于具有ListView SelectedItem的属性和TextBox绑定的ArgumentException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆