2013-09-03 5 views
2

У меня есть ListView в моем приложении, которое в настоящее время заполнено двумя элементами.После повторной установки ItemsSource в WPF ListView он бросает ArgumentException

<ListView Name="lstViewFolderSettings" Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="0" SelectionMode="Single" SelectionChanged="lstViewFolderSettings_SelectionChanged"> 
    <ListView.View> 
     <GridView> 
      <GridViewColumn Width="100" Header="Type" DisplayMemberBinding="{Binding Name}" /> 
      <GridViewColumn Width="250" Header="Folder" DisplayMemberBinding="{Binding FolderPath}" /> 
      <GridViewColumn Width="350" Header="XPath" DisplayMemberBinding="{Binding XPath}" /> 
     </GridView> 
    </ListView.View> 
</ListView> 

Я тогда установка мой ItemsSource как следующий

lstViewFolderSettings.ItemsSource = fileSeperationSettings.FileSettings; 

на SelectionChanged случае я получаю выбранный элемент, который заполнит некоторые элементы управления. Затем я нажмите кнопку Сохранить Затем я обновить мою коллекцию и сбросить ItemsSource снова

lstViewFolderSettings.ItemsSource = null; 
lstViewFolderSettings.ItemsSource = fileSeperationSettings.FileSettings; 

Я должен установить нулевое значение первого в противном случае ListView не обновляется в представлении

Все это, кажется, работает хорошо, пока я не изменить мой выбор дважды на одном и том же элементе.

т.е.
выберите пункт 1 -> изменить -> обновить
выберите пункт 2
выберите пункт 1
выберите пункт 2 -> BANG!

BANG! Я имею в виду это

ArgumentException был необработанным
Элемент с тем же ключом уже был добавлен.

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.Primitives.Selector.SetSelectedHelper(Object item, FrameworkElement UI, Boolean selected) 
at System.Windows.Controls.Primitives.Selector.NotifyIsSelectedChanged(FrameworkElement container, Boolean selected, RoutedEventArgs e) 
at System.Windows.Controls.Primitives.Selector.OnSelected(Object sender, RoutedEventArgs e) 
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.RaiseEvent(RoutedEventArgs e) 
at System.Windows.Controls.ListBoxItem.OnSelected(RoutedEventArgs e) 

--- Update --- SelectionChanged код обработчика событий.

private void lstViewFolderSettings_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    m_SelectedSetting = lstViewFolderSettings.SelectedItem as FileSetting; 
    txtFolder.Text = m_SelectedSetting.FolderPath; 
    txtType.Text = m_SelectedSetting.Name; 
    txtXPath.Text = m_SelectedSetting.XPath; 

    e.Handled = true; 
} 

- Обновлено ----

Так теперь у меня есть этот

ObservableCollection<FileSetting> _fileSettings; 
public ObservableCollection<FileSetting> FileSettings 
{ 
    get 
    { 
     if (_fileSettings == null) 
    { 
      FileSeperationSettings fileSeperationSettings = m_config.GetSection("fileSeperationSettings") as FileSeperationSettings; 

      _fileSettings = new ObservableCollection<FileSetting>(fileSeperationSettings.FileSettings.Cast<FileSetting>()); 
     } 

     return _fileSettings; 
    } 
} 

добавляю и удалить из этой коллекции

FileSettings.Add(fsSetting); 
FileSettings.Remove(fsSetting); 

я получаю выбранный товар

m_SelectedSetting = lstViewFolderSettings.SelectedItem as FileSetting; 

txtFolder.Text = m_SelectedSetting.FolderPath; 
txtType.Text = m_SelectedSetting.Name; 
txtXPath.Text = m_SelectedSetting.XPath; 

я обновить элемент

FileSetting fs = FileSettings.First(x => x.Name == m_SelectedSetting.Name); 
fs.Name = txtType.Text; 
fs.FolderPath = txtFolder.Text; 
fs.XPath = txtXPath.Text; 

Ошибка возникает после того, как я сделать обновление, а затем изменить выбранный элемент во второй раз ...

+0

Ей нужно опубликовать полное исключение, включая трассировку стека ... –

+0

Почему вы обновляете ItemsSource каждый раз? Если объекты в этом списке реализуют INotifyPropertyChanged, вы можете их изменить, а привязка данных WPF обновит интерфейс пользователя для вас. Вы действительно должны только устанавливать этот материал один раз. –

+1

Фактически, если вы можете, используйте привязку данных, чтобы установить источник в первую очередь, а не делать это с кодом. –

ответ

0

Я работал вокруг этого вопроса, прочитав следующее can't clear WPF ListBox.SelectedItems collection я понял, что причина не устранило бы мой SelectedItem был, потому что не существует в коллекции (HashCode изменилось), или что-то с ума, как это ...

Так что я изменил SelectionChanged события следующего

FileSetting selectedItem; 
private void lstViewFolderSettings_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    selectedItem = lstViewFolderSettings.SelectedItem as FileSetting; 
    txtFolder.Text = selectedItem.FolderPath; 
    txtType.Text = selectedItem.Name; 
    txtXPath.Text = selectedItem.XPath; 

    lstViewFolderSettings.UnselectAll(); 
} 

Так что я теперь следить за выбранный элемент самого. Это означает, что я могу установить и повторно установить ItemsSource, как мне заблагорассудится.

+0

Это не «безумный» - вся хэш-код цели используется для хэш-таблиц, чтобы быстро найти объект в хеш-таблице. HashCode объекта должен быть неизменяемым свойством, а не изменяться после создания объекта. Я столкнулся с такой же ошибкой, когда я установил .NET 4.5, который теперь использует хеш-таблицу для выбранных элементов –

0

Я бы отойти от кода-позади и больше использовать привязку данных.

Ваша коллекция должна быть собственностью DataContext пользовательского интерфейса в:

public class MyViewModelOrCodeBehindClass 
{ 
    public FileSetting SelectedItem { get; set; } 

    public ObservableCollection<FileSetting> FileSettings 
    { 
     get; 
     private set; 
    } 

    public MyViewModel() 
    { 
     FileSettings = new ObservableCollection<FileSetting>(); 
     // If you're using codebehind rather than having something 
     // else set this class as the datacontext: 
     DataContext = this; 
    } 
} 

На ваш взгляд:

<ListView ItemsSource="{Binding FileSettings}" SelectedItem="{Binding SelectedItem}" /> 
<TextBlock Text="{Binding SelectedItem.Folder}" /> 
<TextBlock Text="{Binding SelectedItem.Name}" /> 
<TextBlock Text="{Binding SelectedItem.XPath}" /> 

В коде-за/ViewModel вы можете просто добавить/удалить элементы а все остальное. Еще лучше, если каждый элемент в списке реализует INotifyPropertyChanged, тогда редактирование этих элементов также будет автоматически обновляться в пользовательском интерфейсе. Вам не нужно вообще обращаться с SelectionChanged.

+0

У меня была такая же ошибка раньше, и я * делаю * использую привязку данных к * всем * моих элементов управления пользовательского интерфейса, поэтому я не уверен, что это * является * исправлением этой проблемы. Тем не менее, я бы рекомендовал, чтобы пользователь в любом случае использовал эту методологию привязки. – Sheridan

+0

Скорее всего, проблема в его обработчике OnSelected. Я расскажу об этом. –

+0

По-прежнему получать ту же ошибку, следуя тем же шагам, что и выше ... плюс мой пользовательский интерфейс не обрабатывается автоматически. Я нахожу, что мне нужно «CollectionViewSource.GetDefaultView (lstViewFolderSettings) .Refresh();'. –

Смежные вопросы