【发布时间】:2017-07-23 13:16:48
【问题描述】:
编辑:
我发现这个问题的根源是Bar 中的Equals() 和GetHashCode() 实现。
尤其是参与GetHashCode() 并绑定到TextBox 的属性(如Bar 中的Name)。删除这些覆盖方法后一切正常(除了我想保留它们)
我不明白为什么会这样??
我有一个TextBox、一个ListView,以及一些与以下 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 时,绑定有效,并且所选Foo 的FooBar 属性的Name 出现在TextBox 中。无论我更改选择多少次,TextBox 中都会出现相应的值。
但是现在,如果我使用 TextBox 更改 Name(在失去焦点后,由于 TwoWay 数据绑定,它正在工作,我使用调试进行了检查)然后从列表中更改我的选择,@987654343 @ 仍然显示之前选择的项目的值。
此外,再次选择同一个项目,然后选择其他项目时,我得到以下异常(令人惊讶的是,调试器没有报告,我不得不将它记录到文件中。可能是因为异常是不是从我的代码中提出的。)
这是日志:
异常是:-Exception :: System.ArgumentException:一个带有 已添加相同的密钥。在 System.ThrowHelper.ThrowArgumentException(异常资源资源) 在 System.Collections.Generic.Dictionary
2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary2..ctor(IDictionary2 dictionary, IEqualityComparer1 比较器) 在 System.Windows.Controls.Primitives.Selector.InternalSelectedItemsStorage..ctor(InternalSelectedItemsStorage 集合,IEqualityComparer`1 equalComparer) 在 System.Windows.Controls.Primitives.Selector.SelectionChanger.ApplyCanSelectMultiple() 在 System.Windows.Controls.Primitives.Selector.SelectionChanger.End() 在 System.Windows.Controls.Primitives.Selector.SetSelectedHelper(对象 项目,FrameworkElement UI,布尔选择)在 System.Windows.Controls.Primitives.Selector.NotifyIsSelectedChanged(FrameworkElement 容器,布尔选择,RoutedEventArgs e) at System.Windows.Controls.Primitives.Selector.OnSelected(对象发送者, RoutedEventArgs e) 在 System.Windows.RoutedEventHandlerInfo.InvokeHandler(对象目标, RoutedEventArgs routedEventArgs) 在 System.Windows.EventRoute.InvokeHandlersImpl(对象源, RoutedEventArgs 参数,布尔 reRaised)在 System.Windows.UIElement.RaiseEventImpl(DependencyObject 发送者, RoutedEventArgs 参数)在 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 吃 System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs 吃 System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs 参数)在 System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex,DependencyProperty dp,PropertyMetadata 元数据, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference,布尔 coerceWithCurrentValue, 操作类型操作类型)在 System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, 对象值、PropertyMetadata 元数据、布尔值 coerceWithDeferredReference,布尔 coerceWithCurrentValue, OperationType operationType, Boolean isInternal) at System.Windows.DependencyObject.SetCurrentValueInternal(DependencyProperty dp,对象值)在 System.Windows.Controls.ListBox.NotifyListItemClicked(ListBoxItem 项目,鼠标按钮鼠标按钮)在 System.Windows.Controls.ListBoxItem.HandleMouseButtonDown(鼠标按钮 鼠标按钮)在 System.Windows.Controls.ListBoxItem.OnMouseLeftButtonDown(MouseButtonEventArgs e) 在 System.Windows.UIElement.OnMouseLeftButtonDownThunk(Object 发件人,MouseButtonEventArgs e) 在 System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(委托 genericHandler, 对象 genericTarget) 在 System.Windows.RoutedEventArgs.InvokeHandler(委托处理程序,对象 目标)在 System.Windows.RoutedEventHandlerInfo.InvokeHandler(对象目标, RoutedEventArgs routedEventArgs) 在 System.Windows.EventRoute.InvokeHandlersImpl(对象源, RoutedEventArgs 参数,布尔 reRaised)在 System.Windows.UIElement.ReRaiseEventAs(DependencyObject 发件人, RoutedEventArgs 参数,RoutedEvent 新事件)在 System.Windows.UIElement.OnMouseDownThunk(对象发送者, MouseButtonEventArgs e) 在 System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(委托 genericHandler, 对象 genericTarget) 在 System.Windows.RoutedEventArgs.InvokeHandler(委托处理程序,对象 目标)在 System.Windows.RoutedEventHandlerInfo.InvokeHandler(对象目标, RoutedEventArgs routedEventArgs) 在 System.Windows.EventRoute.InvokeHandlersImpl(对象源, RoutedEventArgs 参数,布尔 reRaised)在 System.Windows.UIElement.RaiseEventImpl(DependencyObject 发送者, RoutedEventArgs 参数)在 System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args) 在 System.Windows.UIElement.RaiseEvent(RoutedEventArgs 参数,布尔值 受信任)在 System.Windows.Input.InputManager.ProcessStagingArea() 在 System.Windows.Input.InputManager.ProcessInput(InputEventArgs 输入)在 System.Windows.Input.InputProviderSite.ReportInput(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, Boolean&handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd,Int32 msg,IntPtr wParam, IntPtr lParam,布尔值&处理)在 MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) 在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(委托 回调,对象参数,Int32 numArgs)在 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(对象源, 委托回调、Object args、Int32 numArgs、Delegate catchHandler)
我注意到的另一件值得一提的事情是,如果我将ListView 的SelectionMode 设置为Multiple,则不会引发异常。在这种情况下,List 中的项目,其 FooBar 的值我从 TextBox 更改,保持选中状态,以及我之后可能选择的任何其他项目。
注意:我使用Fody/PropertyChanged来实现INotifyCollectionChanged。
【问题讨论】:
-
福迪?嗯……为什么?我看不出它有什么价值。无论如何..您的虚拟机和视图中有几个问题。
Foos尚未初始化。列表视图没有SelectedItem绑定。为什么不回到基础并尝试使用 INotifyPropertyChanged 实现正确的 MVVM 模型?一旦您知道您可以继续使用 Caliburn。 -
@KosalaW Fody 作为样板的节省时间基本上很好。我非常怀疑这与他的问题有关。
-
@KosalaW 我可能还不是实现 MVVM 的专家,但是,我已经尝试简化我的代码并在这里展示。我不能只是在这里复制粘贴确切的代码,它太长而且大部分是不必要的。
-
@BrandonKramer 基本没问题??还有很多更好的。 OP遇到的问题是非常基本的。 nugets 无法解决这个问题。
-
@KosalaW 我同意 BrandonKramer 的观点,我认为 Fody 不是问题所在。我只是认为人们应该在告诉我在看到 TwoWay 绑定时正确实施 INotifyPropertyChanged 之前了解它。
标签: c# wpf xaml data-binding