3

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.

tshepang
  • 12,111
  • 21
  • 91
  • 136
Dina
  • 1,346
  • 1
  • 15
  • 35
  • Did you try porting this code into a test app and see if you get the same results? – Lee Louviere Jul 10 '13 at 17:06
  • 1
    @Dina, i have checked your code snippet in my VS2012. It is working fine and the bug you raised was not reproducible. Can you try this snippet in a test application and see the issue remain exist. If yes please make the critical section thread safe using c# lock technique. – Vimal CK Jul 10 '13 at 17:08
  • 1
    I can't reproduce the error...can you explain better what you are doing? – sexta13 Jul 10 '13 at 17:13
  • take a look at this: http://stackoverflow.com/questions/604831/collection-was-modified-enumeration-operation-may-not-execute Though this really seems weird behaviour. – Fabian Bigler Jul 10 '13 at 17:24
  • @FabianBigler But, there's no foreach in sight. – Lee Louviere Jul 10 '13 at 18:41
  • @LeeLouviere Yes, I agree, and I couldn't reproduce it either. Seems like a ghost who's playing tricks. ;) – Fabian Bigler Jul 10 '13 at 18:43
  • The code I attached was in fact my entire test repro. I'm running Windows 7 x64, VS 2012 update 2 and the project is .NET 4.0. – Dina Jul 11 '13 at 04:02
  • @Dina That may be all the code related to these fields/data, but did you try isolating the code? Is that all the code in your project? There's nothing there to cause your issue and the people who've copied that code into a new project don't have that issue. – Lee Louviere Jul 16 '13 at 14:09
  • @LeeLouviere This is the entire code. There's nothing else. Like I wrote in my non-complete answer below, the exception comes from deep within WPF and is also caught there. I can see it only when I choose to break when exception are thrown or in the debugging output window. The code works perfectly and the UI is updated whenever needed. However, I don't understand the internals of this and why this happens. I don't understand why List is special and doesn't cause the exception. I'm curious about what's under the hood... – Dina Jul 17 '13 at 14:29

2 Answers2

1

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

Dina
  • 1,346
  • 1
  • 15
  • 35
0

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.

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Lee Louviere
  • 5,162
  • 30
  • 54