我看到很多与此问题相关的帖子,但我找不到解决方案
我有下一个WPF DataGrid:
<DataGrid Grid.Column="1" Grid.Row="4" AutoGenerateColumns="False" ItemsSource="{Binding MapsGrid}" SelectedItem="{Binding DataContext.CategoriesSelectedRow,RelativeSource={RelativeSource AncestorType={x:Type UserControl}},Mode=OneWayToSource}" SelectionMode="Single" CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserAddRows="False"> <DataGrid.Columns> <DataGridTemplateColumn Header="Main Category" Width="*"> <DataGridTemplateColumn.HeaderStyle> <Style TargetType="DataGridColumnHeader"> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="FontSize" Value="16" /> </Style> </DataGridTemplateColumn.HeaderStyle> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox ItemsSource="{Binding MainCategoriesColl}" DisplayMemberPath="Category" SelectedItem="{Binding MainCategorySelectedItem,UpdateSourceTrigger=LostFocus,Mode=OneWayToSource}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Header="Sub Category" Width="*"> <DataGridTemplateColumn.HeaderStyle> <Style TargetType="DataGridColumnHeader"> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="FontSize" Value="16" /> </Style> </DataGridTemplateColumn.HeaderStyle> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ComboBox ItemsSource="{Binding SubCategoriesColl}" DisplayMemberPath="Category" SelectedItem="{Binding SubCategorySelectedItem,Mode=TwoWay}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>
这个DataGrid包含2个ComboBoxes. ItemSource对象是下一个:
public class MapsDescModel : NotificationObject,IEqualityComparer<MapsDescModel>,IEquatable<MapsDescModel> { public MapsDescModel(ObservableCollection<MainCategories> mainCategoty) { MainCategoriesColl = mainCategoty; } public static event Action OnSelectionHandler; private static void OnSelection() { if (OnSelectionHandler != null) { OnSelectionHandler(); } } private MainCategories _mainCategorySelectedItem; public MainCategories MainCategorySelectedItem { get { return _mainCategorySelectedItem; } set { if (Equals(value,_mainCategorySelectedItem)) return; _mainCategorySelectedItem = value; RaisePropertyChanged("MainCategorySelectedItem"); RaisePropertyChanged("SubCategoriesColl"); } } private SubCategories _subCategorySelectedItem; public SubCategories SubCategorySelectedItem { get { return _subCategorySelectedItem; } set { if (Equals(value,_subCategorySelectedItem)) return; _subCategorySelectedItem = value; RaisePropertyChanged("SubCategorySelectedItem"); OnSelection(); } } private ObservableCollection<MainCategories> _mainCategoriesColl; public ObservableCollection<MainCategories> MainCategoriesColl { get { return _mainCategoriesColl; } set { if (Equals(value,_mainCategoriesColl)) return; _mainCategoriesColl = value; RaisePropertyChanged("MainCategoriesColl"); } } //Allow user see N/A category just if is the only subCategory that exists public ObservableCollection<SubCategories> SubCategoriesColl { get { if (MainCategorySelectedItem != null && MainCategorySelectedItem.SubCategory.Any()) if (MainCategorySelectedItem.SubCategory.Count() > 1) { return Infrastructure.Helpers.ExtensionMethods.ToObservableCollection( MainCategorySelectedItem.SubCategory.AsEnumerable().Where(p => p.Category != Infrastructure.Constants.Constants.NoSubCategory)); } else return Infrastructure.Helpers.ExtensionMethods.ToObservableCollection( MainCategorySelectedItem.SubCategory.AsEnumerable()); else return new ObservableCollection<SubCategories>(); } } public bool Equals(MapsDescModel x,MapsDescModel y) { try { if (x.MainCategorySelectedItem == null && y.MainCategorySelectedItem == null) return true; else if (x.MainCategorySelectedItem == null && y.MainCategorySelectedItem != null || x.MainCategorySelectedItem != null && y.MainCategorySelectedItem == null) return false; return x.MainCategorySelectedItem.MainCatID == y.MainCategorySelectedItem.MainCatID && x.SubCategorySelectedItem.SubCatID == y.SubCategorySelectedItem.SubCatID; } catch (Exception ex) { ServiceLocator.Current.GetInstance<Infrastructure.SharedServices.IEnterpriseLibraryLogger>().Log(ex.Message,Category.Exception,Priority.High); return false; } } public int GetHashCode(MapsDescModel obj) { if (Object.ReferenceEquals(obj,null)) return 0; if (obj.MainCategorySelectedItem == null || obj.SubCategorySelectedItem == null) return 0; else return obj.SubCategorySelectedItem.Category.GetHashCode() + obj.MainCategorySelectedItem.GetHashCode(); } public bool Equals(MapsDescModel other) { return this.Equals(this,other); // use definition from IEqualityComparer<T> } public override bool Equals(object obj) { MapsDescModel other = obj as MapsDescModel; if (other == null) return base.Equals(obj); else return this.Equals(other); } public override int GetHashCode() { MapsDescModel other = this as MapsDescModel; if (other == null) return base.GetHashCode(); else return this.GetHashCode(other); } }
一切都很好,除了一个恼人的问题.
当我添加2行时,如果我在附加图片中的标记区域上单击几次,则会出现以下错误:
System.ArgumentException was unhandled HResult=-2147024809 Message=An item with the same key has already been added. Source=mscorlib StackTrace: at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary`2.Insert(TKey key,TValue value,Boolean add) at System.Collections.Generic.Dictionary`2..ctor(IDictionary`2 dictionary,IEqualityComparer`1 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.SelectedItemCollection.EndUpdateSelectedItems() at System.Windows.Controls.Primitives.MultiSelector.EndUpdateSelectedItems() at System.Windows.Controls.DataGrid.MakeFullRowSelection(ItemInfo info,Boolean allowsExtendSelect,Boolean allowsMinimalSelect) at System.Windows.Controls.DataGrid.HandleSelectionForRowHeaderAndDetailsInput(DataGridRow row,Boolean startDragging) at System.Windows.Controls.Primitives.DataGridRowHeader.OnClick() at System.Windows.Controls.Primitives.ButtonBase.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,RoutedEvent newEvent) at System.Windows.UIElement.OnMouseDownThunk(Object sender,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,Boolean& handled) at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd,Boolean& handled) at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback,Object args,Int32 numArgs) at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source,Delegate method,Int32 numArgs,Delegate catchHandler) at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority,TimeSpan timeout,Int32 numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd,IntPtr lParam) at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame) at System.Windows.Threading.Dispatcher.Run() at System.Windows.Application.RunDispatcher(Object ignore) at System.Windows.Application.RunInternal(Window window) at System.Windows.Application.Run(Window window) at System.Windows.Application.Run() at Malaria.App.Main() in c:\My Projects\Hebrew University\Malaria Management Console\Malaria\obj\Debug\App.g.cs:line 0 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly,String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean preserveSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException:
我认为它可能与我的GetHashCode方法有关,但我不确定.
我找到了这个链接
http://leavinsprogramming.blogspot.co.il/2012/08/wpf-datagrid-and-random.html
它描述了我的问题,但那里没有解决方案.
有谁知道为什么会发生这种异常?
解决方法
引用
MSDN’s entry on Object.GetHashCode():
@H_404_25@
In general,for mutable reference types,you should override GetHashCode only if:
-
You can compute the hash code from fields that are not mutable; or
-
You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
您当前的GetHashCode()实现调用GetHashCode(MapsDescModel obj),该方法依赖于可在集合中更改的可变字段.
更改GetHashCode()实现以返回不依赖于可更改字段的值.