1

I have an issue regarding cross thread calls in WPF.

            foreach (RadioButton r in StatusButtonList)
        {
            StatusType status = null;
            r.Dispatcher.Invoke(new ThreadStart(() => status= ((StatusButtonProperties)r.Tag).StatusInformation));
            if (AppLogic.CurrentStatus == null || AppLogic.CurrentStatus.IsStatusNextLogical(status.Code))
            {
                SolidColorBrush green = new SolidColorBrush(Color.FromRgb(102, 255, 102));
                r.Dispatcher.Invoke(new ThreadStart(() =>  r.Background = green));
            }
            else
            {
                SolidColorBrush red = new SolidColorBrush(Color.FromRgb(255, 0, 0));
                r.Dispatcher.Invoke(new ThreadStart(() => r.Background = red));
            }
        }

When I run this code, it works correctly for the first iteration. However during the second iteration the line:

  r.Dispatcher.Invoke(new ThreadStart(() => status= ((StatusButtonProperties)r.Tag).StatusInformation))

Causes this exception:

Cannot use a DependencyObject that belongs to a different thread than its parent Freezable.

I've tried a few solutions but I can't find anything workable.

Any help appreciated!

  • 2
    Creating SolidColorBrush red + green in a thread which is not the same as r.Dispatcher.Invoke...? – Michal Ciechan May 03 '11 at 11:04
  • Why are you using a new thread for those setters? Since you are using Invoke(), it is blocking until that thread is finished with its work, so it probably slows the whole thing down. – Daniel Rose May 03 '11 at 11:06

3 Answers3

5

I'd rewrite this to:

r.Dispatcher.Invoke(new Action(delegate()
{
    status = ((StatusButtonProperties)r.Tag).StatusInformation;

    if (AppLogic.CurrentStatus == null || AppLogic.CurrentStatus.IsStatusNextLogical(status.Code))
    {
        r.Background = Brushes.Green;
    }
    else
    {
        r.Background = Brushes.Red;
    }

}));
Thorsten Dittmar
  • 55,956
  • 8
  • 91
  • 139
3
    r.Dispatcher.Invoke(
      System.Windows.Threading.DispatcherPriority.Normal,
      new Action(
        delegate()
        {
                // DO YOUR If... ELSE STATEMNT HERE
        }
    ));
Michal Ciechan
  • 13,492
  • 11
  • 76
  • 118
1

I am assuming that you are in a different thread than the one which created those RadioButtons. Otherwise the invoking makes no sense. Since you are creating the SolidColorBrush in that thread, you already have a potential cross-thread call there.

It would make more sense to make the cross-thread calls more "chunky", i.e. put everything in the foreach loop in a single Invoke call.

foreach (RadioButton r in StatusButtonList)
{
    r.Dispatcher.Invoke(new ThreadStart(() => 
        {
            StatusType status = ((StatusButtonProperties)r.Tag).StatusInformation;
            if (AppLogic.CurrentStatus == null || AppLogic.CurrentStatus.IsStatusNextLogical(status.Code))
            {
                SolidColorBrush green = new SolidColorBrush(Color.FromRgb(102, 255, 102));
                r.Background = green;
            }
            else
            {
                SolidColorBrush red = new SolidColorBrush(Color.FromRgb(255, 0, 0));
                r.Background = red;
            }
        });
}

You could also consider using BeginInvoke if the different calls are not interdependant.

Daniel Rose
  • 17,233
  • 9
  • 65
  • 88