wpf DataGrid - 已添加具有相同键的项

时间:2013-04-12 08:51:42

标签: c# wpf mvvm datagrid

我看到很多与此问题相关的帖子,但我找不到解决方案

我有下一个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,  UpdateSourceTrigger=LostFocus, 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, 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 MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
       at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
       at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, 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, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

我认为它可能与我的GetHashCode方法有关,但我不确定。 我找到了这个链接 http://leavinsprogramming.blogspot.co.il/2012/08/wpf-datagrid-and-random.html 它描述了我的问题,但那里没有解决方案。 有谁知道为什么会发生这种异常?

The problematic area

2 个答案:

答案 0 :(得分:10)

引用MSDN's entry on Object.GetHashCode()

  

通常,对于可变引用类型,只应在以下情况下覆盖GetHashCode:

     
      
  • 您可以从不可变的字段计算哈希码;或

  •   
  • 当对象包含在依赖于其哈希码的集合中时,您可以确保可变对象的哈希码不会更改。

  •   

您当前的GetHashCode()实现调用了GetHashCode(MapsDescModel obj),该方法依赖于可在集合中更改的可变字段。

更改GetHashCode()实施,以返回不依赖于可更改字段的值。

答案 1 :(得分:0)

我认为MapsGrid是一个实体集合,当你为第二个记录添加第二条同样[Key]的记录时。

对于您的实体,您应该提供不同的密钥。