Click here to Skip to main content
15,888,454 members
Please Sign up or sign in to vote.
4.00/5 (1 vote)
See more:
Hello,

I'm getting always a exception when I'm changing the DataGrid. The DataGrids ItemsSource is bound to an ObservableCollection.

I have the following code (only the important code is shown, if something is missing, I will complete it):
Models
Locale.cs:
C#
public class Locale
{
    private ObservableCollection<LocaleEntry> entries;

    public Locale()
    {
        this.entries = new ObservableCollection<LocaleEntry>();
        this.entries.CollectionChanged += new NotifyCollectionChangedEventHandler(this.entries_CollectionChanged);
    }

    public ObservableCollection<LocaleEntry> Entries
    {
        get { return this.entries; }
        set
        {
            if (this.entries.Equals(value))
            {
                return;
            }

            this.entries = value;
            this.OnPropertyChanged("Entries");
        }
    }

    public override bool Equals(object obj)
    {
        if (!obj.GetType().Equals(this.ObjectType))
        {
            return false;
        }

        Locale locale = (Locale)obj;
        if (!this.Name.Equals(locale.Name))
        {
            return false;
        }

        if (!this.Entries.Count.Equals(locale.Entries.Count))
        {
            return false;
        }

        foreach (LocaleEntry localeEntry in this.Entries)
        {
            if (!locale.Entries.Contains(localeEntry))
            {
                return false;
            }
        }

        return true;
    }
}


LocaleEntry.cs
C#
public class LocaleEntry
{
    private string language;
    private string value;

    public LocaleEntry()
    {
        this.language = string.Empty;
        this.value = string.Empty;
    }

    public string Language 
    {
        get { return this.language; }
        set
        {
            if (value == this.language || string.IsNullOrEmpty(value))
            {
                return;
            }

            this.language = value;
            this.OnPropertyChanged("Language");
        }
    }

    public string Value 
    {
        get { return this.value; }
        set
        {
            if (value == this.value || string.IsNullOrEmpty(value))
            {
                return;
            }

            this.value = value;
            this.OnPropertyChanged("Value");
        }
    }

    public override bool Equals(object obj)
    {
        if (obj == null)
        {
            return false;
        }

        if (obj.GetType() != typeof(LocaleEntry))
        {
            return false;
        }

        LocaleEntry locale = (LocaleEntry)obj;
        if (!locale.Language.Equals(this.Language))
        {
            return false;
        }

        if (!locale.Value.Equals(this.Value))
        {
            return false;
        }

        return true;
    }
}



ViewModel
C#
class UserControlLocaleEntryBase : ViewModelBase
{
    private Locale locale;

    private RelayCommand addLocaleEntry;
    private RelayCommand removeLocaleEntry;

    private int selectedIndex;

    public UserControlLocaleEntryBase(Locale locale)
    {
        this.Locale = locale;
        this.selectedIndex = -1;
    }

    public int SelectedIndex
    {
        get
        {
            return this.selectedIndex;
        }

        set
        {
            if (this.selectedIndex.Equals(value))
            {
                return;
            }

            this.selectedIndex = value;
            this.OnPropertyChanged("SelectedIndex");
        }
    }

    public Locale Locale
    {
        get { return this.locale; }
        set
        {
            if (this.locale != null && this.locale.Equals(value))
            {
                return;
            }

            this.locale = value;
        }
    }

    public ICommand AddLocaleEntry
    {
        get
        {
            if (this.addLocaleEntry == null)
            {
                this.addLocaleEntry = new RelayCommand(() => this.addLocaleEntryFunc());
            }

            return this.addLocaleEntry;
        }
    }

    public ICommand RemoveLocaleEntry
    {
        get
        {
            if (this.removeLocaleEntry == null)
            {
                this.removeLocaleEntry = new RelayCommand(() => this.removeLocaleEntryFunc(), () => this.canRemoveLocaleEntry);
            }

            return this.removeLocaleEntry;
        }
    }

    private void addLocaleEntryFunc()
    {
        LocaleEntry localeEntry = new LocaleEntry();
        if (!this.Locale.Entries.Contains(localeEntry))
        {
            this.Locale.Entries.Add(localeEntry);
        }
    }

    private void removeLocaleEntryFunc()
    {
        this.Locale.Entries.RemoveAt(this.SelectedIndex);
    }

    private bool canRemoveLocaleEntry
    {
        get
        {
            if (this.selectedIndex.Equals(-1))
            {
                return false;
            }

            return true;
        }
    }
}


View
UserControlLocaleEntry.xaml.cs:
C#
public partial class UserControlLocaleEntry : UserControl
{
    private readonly UserControlLocaleEntryBase userControlLocaleEntryBase;

    public UserControlLocaleEntry(Locale locale)
    {
        InitializeComponent();
        this.userControlLocaleEntryBase = new UserControlLocaleEntryBase(locale);
        base.DataContext = this.userControlLocaleEntryBase;
    }
}


UserControlLocaleEntry.xaml:
XML
<UserControl x:Class="SAP_Installation_Designer_2.UserControlLocaleEntry"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:t="clr-namespace:TestApp.Translation"
             Height="Auto" Width="Auto">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBlock Grid.Column="0" Margin="6" VerticalAlignment="Center" Text="{t:Translate strUserControlLocaleEntryName}"/>
            <TextBox Grid.Column="1" Margin="6" VerticalAlignment="Center">
                <TextBox.Text>
                    <Binding Path="Locale.Name" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
                </TextBox.Text>
            </TextBox>
        </Grid>
        <DataGrid Grid.Row="1" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow" CanUserAddRows="False" CanUserDeleteRows="False">
            <DataGrid.ItemsSource>
                <Binding Path="Locale.Entries" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
            </DataGrid.ItemsSource>
            <DataGrid.SelectedIndex>
                <Binding Path="SelectedIndex" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
            </DataGrid.SelectedIndex>
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Path=Language, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="{t:Translate strUserControlLocaleEntryLanguage}" Width="Auto"/>
                <DataGridTextColumn Binding="{Binding Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="{t:Translate strUserControlLocaleEntryValue}" Width="*"/>
            </DataGrid.Columns>
        </DataGrid>
        <Grid Grid.Row="2">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Button Grid.Column="0" Height="25" MinWidth="75" Margin="6" Command="{Binding Path=AddLocaleEntry}">
                <StackPanel Orientation="Horizontal">
                    <Image Source="../../Resources/GreenPlus16.png" Margin="6,0,0,0" VerticalAlignment="Center"/>
                    <TextBlock Text="{t:Translate strUserControlLocaleEntryAdd}" Margin="6,0,6,0" VerticalAlignment="Center"/>
                </StackPanel>
            </Button>
            <Button Grid.Column="2" Height="25" MinWidth="75" Margin="6" Command="{Binding Path=RemoveLocaleEntry}">
                <StackPanel Orientation="Horizontal">
                    <Image Source="../../Resources/Redx16.png" Margin="6,0,0,0" VerticalAlignment="Center"/>
                    <TextBlock Text="{t:Translate strUserControlLocaleEntryRemove}" Margin="6,0,6,0" VerticalAlignment="Center"/>
                </StackPanel>
            </Button>
        </Grid>
    </Grid>
</UserControl>


I'm able to see all rows in the DataGrid and also inserting or removing items from the collection is working without any problems. But if I change an item (Click in a row and change the text inside) I always get this ArgumentException:

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.HandleSelectionForCellInput(DataGridCell cell, Boolean startDragging, Boolean allowsExtendSelect, Boolean allowsMinimalSelect)
       at System.Windows.Controls.DataGridCell.OnAnyMouseLeftButtonDown(MouseButtonEventArgs e)
       at System.Windows.Controls.DataGridCell.OnAnyMouseLeftButtonDownThunk(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 Test.App.Main() in C:\Source\App.g.cs:line 0
  InnerException: 


I'm confused with this exception, as I'm not adding a new item, there is only a change in a existing item. What am I missing? Whats wrong with my code? Can someone help me?

Thanks in advance,
Libor
Posted
Comments
Tobias Walter 12-Nov-12 2:39am    
I get the same exception when editing a WPF datagrid, but that code worked for me before. And it also works on the machines of my coworkers. The only difference was that I installed Visual Studio 2012. Still investigating...

1 solution

I have a solution for my problem.

I defined my DataGrid with following attributes:
SelectionMode="Single" SelectionUnit="FullRow"


I tried to use one of them an I always get the issue when SelectionMode="Single" is used. Without this attribute, everything works as expected.

This is ok for me, maybe it helps someone.

Best Regards,
Libor
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900