-3

I create Button in my c# kod and add this button to dictionary. I have method to run buttons. When i run this method in Task it make exception:

The calling thread cannot access this object because it belongs to a different thread.

private void RefreshTags()
    {
        var r = new Random();
        lock (dictTagModel)
        {
            foreach (var item in dictTagModel)
            {
                Canvas.SetLeft(item.Value, r.Next(1, 1400));
            }
        }
    }
    private void btn1_Click(object sender, RoutedEventArgs e)
    {
        var r = new Random();
        listTagModel.Add(new TagModel { TagMac = r.Next(1, 10) });
        lock (dictTagModel)
        {
            foreach (var tag in listTagModel)
            {

                if (!dictTagModel.ContainsKey(tag.TagMac))
                {

                    var button1 = new Button
                    {
                        //Name = item.Angle.ToString(),
                        Background = Brushes.Black,
                        Height = 8,
                        Width = 8,
                        Content = 0.ToString(),
                        FontSize = 10,
                    };
                    Canvas.SetLeft(button1, 100);
                    Canvas.SetTop(button1, tagHight);
                    canvas.Children.Add(button1);
                    dictTagModel.Add(tag.TagMac, button1);
                    tagHight -= 10;
                }
            }
        }
        if(tagHight == 325)
        {
            Task.Run(() =>
            {
                while (true)
                {
                    Thread.Sleep(1000);
                    RefreshTags();
                }
            });
        }
    }

When it isnt in Task and i only run 1 time this method it work.

  • `Task.Run()` is running on a separate thread, and cannot directly invoke the UI thread. Look at `Dispatcher.Invoke` – Barry O'Kane Oct 23 '19 at 09:28
  • That infinite(!) loop in Task.Run looks odd. Besides that is should somehow terminate, it should also be awaited, i.e. called like `await Task.Run(...)`. The `btn1_Click` method would have to be declared `async`. Then you could avoid `Dispatcher.Invoke` by a loop over `await Task.Delay(1000); RefreshTags();`, without Task.Run. – Clemens Oct 23 '19 at 09:56

1 Answers1

-1

You can only access UI elements from the UI thread. If you're inside Task.Run(...), your code is running in a background thread which cannot access the WPF controls -> hence the exception you mentioned.

Wrap the call to RefreshTags() inside a Dispatche.Invoke() call:

await Task.Run(() =>
{
    while (true)
    {
        Thread.Sleep(1000);
        Dispatcher.Invoke(() =>
        {
             RefreshTags();
        });
     }
});

Better don't use Task.Run and Dispatcher.Invoke at all:

while (true)
{
    await Task.Delay(1000);
    RefreshTags();
}
Clemens
  • 123,504
  • 12
  • 155
  • 268
Andreas
  • 224
  • 1
  • 7