0

I am trying to display a menu element in my application as soon as a specific bluetooth message arrives. The messages are collected and interpreted through a timer method and if the correct message arrives, the element should be rendered visible. I keep getting an exception telling me that the object is owned by another thread and cannot be accessed.

// Shows a TangibleMenu element
private void Show(TangibleMenu TangibleMenuElement)
{
    if (TangibleMenuElement.Shape.CheckAccess())
    {
        Debug.WriteLine("normal show");
        TangibleMenuElement.Shape.Opacity = 1;
        TangibleMenuElement.Shape.Visibility = System.Windows.Visibility.Visible;
        this.ParentContainer.Activate(TangibleMenuElement.Shape);
    }
    else
    {
        Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
        {
            Debug.WriteLine("dispatcher show");
            TangibleMenuElement.Shape.Opacity = 1; // EXCEPTION HERE
            TangibleMenuElement.Shape.Visibility = System.Windows.Visibility.Visible;
            this.ParentContainer.Activate(TangibleMenuElement.Shape);
        }));
    }
}

I thought that this exact issue could be solved by using the Dispatcher but in this case, it doesn't seem to work. TangibleMenuElement.Shape is a ScatterViewItem from the Microsoft Surface SDK. Does anyone have any suggestions?

xmashallax
  • 1,673
  • 1
  • 17
  • 34

3 Answers3

0

TangibleMenuElement needs to be created on the UI thread, not just added to the container on the UI thread. This means you'll need to construct the FrameworkElement completely on the UI thread.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • It is already created, I just want to change properties. Is that possible? – xmashallax Oct 23 '13 at 22:47
  • @xmashallax The fact that you are getting the exception suggests that it was created on the wrong thread. It needs to be constructed and modified on the UI thread. – Reed Copsey Oct 23 '13 at 22:47
  • How do I instruct the UI thread to change properties from a different thread? I thought I was doing this but obviously I wasn't. – xmashallax Oct 23 '13 at 22:49
  • @xmashallax You're doing it properly - the problem isn't this method (I don't think) - it's the method where you construct `TangibleMenuElement` (in this case, where you create the `Shape` property on that class) – Reed Copsey Oct 23 '13 at 23:03
  • `TangibleMenuElement` is created on the main thread. The command to change the visibility is fetched in a different thread and this thread needs to instruct the main thread to execute the changes. – xmashallax Oct 23 '13 at 23:10
  • @xmashallax What about `MenuElement.Shape`? That's the actual object that seems to be causing the issue here... – Reed Copsey Oct 23 '13 at 23:24
  • Found the solution ... I accessed the wrong Dispatcher, it had nothing to do with the `TangibleMenuElement`. Thx for your comments, they helped finding the solution :) – xmashallax Oct 23 '13 at 23:54
0

try this

// Shows a TangibleMenu element
private void Show(TangibleMenu TangibleMenuElement)
{
    App.Current.Dispatcher.Invoke(new Action(() =>
    {
        if (TangibleMenuElement.Shape.CheckAccess())
        {
            Debug.WriteLine("normal show");
            TangibleMenuElement.Shape.Opacity = 1;
            TangibleMenuElement.Shape.Visibility = System.Windows.Visibility.Visible;
            this.ParentContainer.Activate(TangibleMenuElement.Shape);
        }
        else
        {
            Debug.WriteLine("dispatcher show");
            TangibleMenuElement.Shape.Opacity = 1; // EXCEPTION HERE
            TangibleMenuElement.Shape.Visibility = System.Windows.Visibility.Visible;
            this.ParentContainer.Activate(TangibleMenuElement.Shape);
        }
    }));
}
Tony
  • 16,527
  • 15
  • 80
  • 134
0

Solution to my problem: I accessed the wrong Dispatcher ...

I did not pay attention to the difference between Dispatcher.CurrentDispatcher and Application.Current.Dispatcher. The first one returns the dispatcher for the current thread, the second one returns the UI thread in my case (first thread of the application).

So my Timer thread got the message, called Show(), asked for a Dispatcher and got one ... but it was the Dispatcher of the Timer thread and not the UI thread. When I changed the code to Application.Current.Dispatcher it worked as expected.

A more detailled explanation can be found here.

Community
  • 1
  • 1
xmashallax
  • 1,673
  • 1
  • 17
  • 34