Dina
Dina

Reputation: 1406

Exception while Refresh-ing Items of ListBox

I have a WFP application with a ListBox and a Button:

<Window x:Class="UITester.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
    Title="MainWindow" Height="350" Width="525">
        <ListBox Name="list"></ListBox>
        <Button Click="ButtonSelect_OnClick">Select Stuff</Button>
</Window>

In the code behind I have this:

public partial class MainWindow : Window
{
    private readonly Dictionary<int, int> _selected = new Dictionary<int, int>();

    public MainWindow()
    {
        InitializeComponent();

        list.ItemsSource = _selected.Values;
    }

    private void ButtonSelect_OnClick(object sender, RoutedEventArgs e)
    {
        _selected.Clear();
        for (int i = 0; i < 4; ++i)
        {
            _selected.Add(i, i);                
        }

        list.Items.Refresh();
    }
}

If I run the application without a debugger attached everything seems all right - I click the button and the number 0 to 3 appear in the list.

However, if I run this with a debugger attached I see that when calling the line list.Items.Refresh(); there's an exception thrown:

Collection was modified; enumeration operation may not execute.

As far as I know, this exception is thrown when trying to change a collection while enumerating it. But I'm pretty sure this isn't the case. Everything here happens in the UI thread. First I add elements to the dictionary and only once that's done, I refresh the items in the list box. It seems to me that nothing is changed and in fact, nothing is enumerated. I suppose that the Refresh method enumerates the dictionary's values, but they have already been updated and are not changed during this enumeration.

I know this is not the best way to update a ListBox, but it's part of a much larger and older code, and I just want to understand what's wrong here.

UPDATE

When I change _selected to be List<int> and set list.ItemsSource = _selected; then there's no exception and no warnings in the output window. But when I set _selected to be 'HashSet` then the problems come back.

Upvotes: 3

Views: 551

Answers (2)

Dina
Dina

Reputation: 1406

This is not a complete answer, since I still don't understand why this happens and what's going on under the hood, but I have convinced myself that I shouldn't be worried about this. The exception occurres deep inside the WPF framework and is probably caught somewhere there. I can only see there's an exception when running with a debugger by looking at the output window:

A first chance exception of type 'System.InvalidOperationException' occurred in mscorlib.dll

And only if I choose to break when the exception is thrown then the debugger indeed breaks. There are no unhandled exceptions.

So while the real reason for this is still a mystery, it would seem that the problem is not in my code...

Upvotes: 1

Lee Louviere
Lee Louviere

Reputation: 5262

It would be better to maintain your own list separate from the Dictionary and copy values over when the Dictionary changes. I'd advise using an ObservableCollection, so you don't have to do a refresh call.

I swear I still have my code for an ObservableDictionary somewhere.

Upvotes: 0

Related Questions