views:

935

answers:

3

I have an application which has an asynchronous operation built into it that loops over a large number of items and performs lengthy calculations on each item, as this occurs certain conditions will cause the application to pop up a modal dialog for user input. Interestingly, I noticed while running this today that in one application instance the modal dialogs somehow got the wrong parent form- rather than providing a modal block to my application the dialogs had taken a Digsby chat window as their parent.

The Digsby window that they became children of popped up around the same time as the first dialog was created (possibly the exact same time) and it would seem that they threads somehow crossed one another because the Digsby window became completely blocked until the async operation completed. I do not know how this is possible considering how per-process threading works, but it certainly did happen. What would cause such a bug? The application is C# .NET 3.5 with Windows Forms running on Windows XP, by the way.

Here's the async code in a nutshell:

Action<List<ClubListing>> a = delegate(List<ClubListing> list)
        {
            for (int i = 0; i < list.Count; i++)
            {
                var cl = list[i];
                if (cl.MatchingClubListing == null)
                {
                    var compare = CompareNames(cl.Club.Name);
                    if (compare.Any(c => c.Value == 0 && c.Key.Club.State == cl.Club.State))
                    {
                        var match = compare.First(c => c.Value == 0 && c.Key.Club.State == cl.Club.State);
                        compareDialog.ClubA = cl.Club;
                        compareDialog.ClubB = match.Key.Club;
                        DialogResult dr = compareDialog.ShowDialog();
                        if (dr == DialogResult.Yes)
                        {
                            cl.MatchingClubListing = match.Key;
                            match.Key.MatchingClubListing = cl;
                        }
                        else if (dr == DialogResult.Abort)
                        {
                            break;
                        }
                    }
                }
                this.Invoke(new MethodInvoker(delegate()
                {
                    this.prbOperationProgress.Value = i;
                }));
            }
        };

        AsyncCallback callback = new AsyncCallback(SaveAndUpdate);
        var result = a.BeginInvoke(this.lbxLiveClubs.Items.Cast<ClubListing>().ToList(), callback, null);
A: 

Just as you're Invoking your ProgressBar update, you need to Invoke() the showing of your dialog.

Adam Robinson
+3  A: 

Add the parent dialog as argument to compareDialog.ShowDialog(). Eg:

Form parent = ...;
compareDialog.ShowDialog(parent);
Hallgrim
The reason this is the answer is that the docs for the no-argument ShowDialog() say: "...the currently active window is made the owner of the dialog box. If you want to specify a specific owner, use the other version of this method." See http://msdn.microsoft.com/en-us/library/c7ykbedk.aspx
Andrew Watt
A: 

It looks like you are showing your compare dialog in the worker thread. I think you may be okay if you use a call to Invoke to show your dialog.

Matt Brunell