1
votes

I'm encountering an InvalidOperationException with the message "The calling thread must be STA, because many UI components require this." in my WPF application development. (See below the code with the location where the error is happening). The error happens inside Participant constructor, as Canvas gui is being constructed and the Canvas constructor itself is throwing this exception, not entering the constructor.

public class Participant : SktParticipant
    {
        public enum PictureMode
        {
            Avatar,
            Video
        }

        public PictureMode pictureMode = PictureMode.Avatar;

        public Canvas gui;
        public VerticalProgressBar voiceVolume;
        public Label nameLabel;
        public VideoRenderer pic;
        public Video video;

        public bool isCachedInClient = false;   // indicates whether displayName and avatarImage have values
        public string displayName = null;
        public Image avatarImage = null;

        public int picHeight = 480;
        public int piclWidth = 640;
        public int panelHeight = 155;
        public int panelWidth = 174;

        public System.Drawing.Color liveColor = System.Drawing.SystemColors.GradientActiveCaption;
        public System.Drawing.Color nonLiveColor = System.Drawing.SystemColors.GradientActiveCaption;

        public Participant(uint objectId, SktSkype skype)
            : base(objectId, skype)
        {
            gui = new Canvas()  //HERE IS THE InvalidOperationException ERROR
            {
                Width = panelWidth,
                Height = panelHeight,
                //BorderStyle = BorderStyle.FixedSingle,
                Background = System.Windows.SystemColors.GradientActiveCaptionBrush
            };
            pic = new VideoRenderer(skypeRef)
            {
                Margin = new System.Windows.Thickness { Left = 5, Top = 5, Right = 0, Bottom = 0 },
                Height = picHeight,
                Width = piclWidth,
                Stretch = Stretch.Fill
            };
            gui.Children.Add(pic);

I've read about STA and MTA threading (e.g. "The calling thread must be STA, because many UI components require this." WPF), but I can't set the thread which creates a new Participant to STA.. I’ve not been able to locate which is the thread / method that is calling it, when the error occurs. I’ve seen that the Participant contructor is called with no problems from the following code:

private void callButton_Click(object sender, EventArgs e)
        {
            if (liveSession != null)
            {
                if ((liveSession.P_LOCAL_LIVESTATUS == SktConversation.LOCAL_LIVESTATUS.RINGING_FOR_ME) || 
                    (liveSession.P_LOCAL_LIVESTATUS == SktConversation.LOCAL_LIVESTATUS.OTHERS_ARE_LIVE))
                {
                    liveSession.JoinLiveSession("");
                }
                else
                {
                    if (liveSession == null) return;
                    // if we leave volountarily, while other people are still in a live session,
                    // the liveSession P_LOCAL_LIVESTATUS will remain OTHERS_ARE_LIVE.
                    // So, we need to switch UI mode to not-yet-in-call state here as well.
                    liveSession.LeaveLiveSession(false);
                    liveSession = null;
                    ReleaseWebcam();
                    UiToWaitingMode();
                }
                return;
            }

            if (convListBox.SelectedItem == null) return;

            // Here we actually make the outgoing call
            Conversation conv = (Conversation)convListBox.Items[convListBox.SelectedIndex];
            liveSession = conv;

            // Fetching target list from conv and converting to string list
            SktParticipant.List parts;
            parts = liveSession.GetParticipants(SktConversation.PARTICIPANTFILTER.OTHER_CONSUMERS);             
            foreach (Participant p in parts) { p.RingIt(); }
        }

I've tried to pin down where the error is coming from, using dispatchers of various threads and objects, ensured main() has STAthread attribute, tried setting "[STAThread]" on seemingly relevant methods.

Does somebody know how I can solve this error?

1
From where are you instantiating the Participant constructor? On a side note you must always create UI elements on Main thread instead of background thread.Rohit Vats
Just look at the Call Stack debugger window to see how you got there. Most likely due to some kind event that was raised on a thread pool thread.Hans Passant

1 Answers

1
votes

The problem is that in the second case, your code is called by the UI thread, but in the first case I suppose it is one of your worker/communication threads. In WPF, all UI changes must be either done in the UI thread or dispatched to it using a special Dispatcher object.

Wrap your UI changes to a separate method and use Application.Current.Dispatcher.Invoke to call it.

Here's a more detailed article about this issue and its solution: http://blog.decarufel.net/2009/03/good-practice-to-use-dispatcher-in-wpf.html