使用DataGrid,ObservableCollection和MVVM进行更改时发生异常 [英] Exception on change with DataGrid, ObservableCollection and MVVM

查看:98
本文介绍了使用DataGrid,ObservableCollection和MVVM进行更改时发生异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好,

更改DataGrid时总是出现异常. DataGrids ItemsSource绑定到ObservableCollection.

我有以下代码(仅显示重要的代码,如果缺少某些内容,我将完成它):
模型
Locale.cs:

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:

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



LocaleEntry.cs

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




ViewModel

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;
        }
    }
}



查看
UserControlLocaleEntry.xaml.cs:



View
UserControlLocaleEntry.xaml.cs:

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:



UserControlLocaleEntry.xaml:

<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>



我可以看到DataGrid中的所有行,并且可以从集合中插入或删除项目,而且没有任何问题.但是,如果我更改项目(单击并更改其中的文本),则始终会收到此ArgumentException:



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: 



我对此例外感到困惑,因为我没有添加新项目,所以现有项目中只有一个更改.我想念什么?我的代码有什么问题?有人可以帮我吗?

预先感谢,
Libor



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

推荐答案

我有解决问题的方法.

我使用以下属性定义了DataGrid:
I have a solution for my problem.

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



我尝试使用其中之一,但在使用SelectionMode ="Single"时总是会遇到问题.没有此属性,一切都会按预期进行.

This is ok for me, maybe it helps someone.

Best Regards,
Libor



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


这篇关于使用DataGrid,ObservableCollection和MVVM进行更改时发生异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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