Reputation: 2406
I have a ListView
within my application which is currently populated with 2 items.
<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>
I am then setting my ItemsSource
like the following
lstViewFolderSettings.ItemsSource = fileSeperationSettings.FileSettings;
on SelectionChanged
event I get the selected item which populates some controls. I then click save I then update my collection and reset the ItemsSource
again
lstViewFolderSettings.ItemsSource = null;
lstViewFolderSettings.ItemsSource = fileSeperationSettings.FileSettings;
I have to set to null first otherwise the ListView
does not update in the view
This all seems to work fine until I change my selection twice on the same item.
i.e.
select item 1 -> change -> update
select item 2
select item 1
select item 2 -> BANG!
The BANG! I refer to is
ArgumentException was unhandled
An item with the same key has already been added.
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 event handler code.
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;
}
-- Updated ----
So I now have this
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;
}
}
I add and remove from this collection
FileSettings.Add(fsSetting);
FileSettings.Remove(fsSetting);
I get the selected Item
m_SelectedSetting = lstViewFolderSettings.SelectedItem as FileSetting;
txtFolder.Text = m_SelectedSetting.FolderPath;
txtType.Text = m_SelectedSetting.Name;
txtXPath.Text = m_SelectedSetting.XPath;
I update the item
FileSetting fs = FileSettings.First(x => x.Name == m_SelectedSetting.Name);
fs.Name = txtType.Text;
fs.FolderPath = txtFolder.Text;
fs.XPath = txtXPath.Text;
The error occurs after I do an update and then change the selected Item for the second time...
Upvotes: 3
Views: 2436
Reputation: 2406
I worked around this issue by reading the following can't clear WPF ListBox.SelectedItems collection I realised that the reason it would not remove my selectedItem was because it did not exist in the collection (HashCode had changed), or something mad like that...
So I changed the selectionChanged event to the following
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();
}
So I now keep track of the selected item myself. This means I can set and re-set the ItemsSource as I please.
Upvotes: 1
Reputation: 42155
I'd move away from the code-behind and make more use of data binding.
Your collection should be a property of the UI's 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;
}
}
In your view:
<ListView ItemsSource="{Binding FileSettings}" SelectedItem="{Binding SelectedItem}" />
<TextBlock Text="{Binding SelectedItem.Folder}" />
<TextBlock Text="{Binding SelectedItem.Name}" />
<TextBlock Text="{Binding SelectedItem.XPath}" />
In your code-behind/viewmodel you can then just add/remove items and the databinding will do the rest. Even better, if each item in the list implements INotifyPropertyChanged
, then edits to those items will also be automatically updated in the UI. You shouldn't need to handle SelectionChanged
really at all.
Upvotes: 0