重新设置WPF ListView的ItemsSource后,它会抛出ArgumentException

时间:2013-09-03 13:13:05

标签: c# wpf listview

我的应用程序中有ListView,目前填充了2个项目。

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

我必须先设置为null,否则ListView不会在视图中更新

这一切似乎都能正常工作,直到我在同一项目上更改我的选择两次。

即。
选择项目1 - &gt;改变 - &gt;更新
选择项目2
选择项目1
选择项目2 - &gt; BANG!

砰!砰!我指的是

ArgumentException未处理
已添加具有相同密钥的项目。

堆栈跟踪:

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)

---更新--- 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;

我做更新后再发生错误,然后第二次更改所选项目......

2 个答案:

答案 0 :(得分:1)

我通过阅读以下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。

答案 1 :(得分: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}" />

在您的代码隐藏/视图模型中,您可以只添加/删除项目,数据绑定将完成剩下的工作。更好的是,如果列表中的每个项目都实现INotifyPropertyChanged,那么对这些项目的编辑也将在UI中自动更新。你根本不需要真正处理SelectionChanged