1

我遇到了 InvalidOperationException 消息“调用线程必须是 STA,因为许多 UI 组件都需要这个。” 在我的 WPF 应用程序开发中。(请参阅下面的代码以及发生错误的位置)。错误发生在 Participant 构造函数中,因为 Canvas gui 正在构造中,并且 Canvas 构造函数本身抛出此异常,而不是进入构造函数。

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);

我已经阅读了有关 STA 和 MTA 线程的信息(例如“调用线程必须是 STA,因为许多 UI 组件都需要这个。” WPF),但我无法将创建新参与者的线程设置为 STA .. 我已经发生错误时,无法找到调用它的线程/方法。我已经看到,从以下代码调用 Participant 构造函数没有问题:

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(); }
        }

我试图确定错误的来源,使用各种线程和对象的调度程序,确保 main() 具有 STAthread 属性,尝试在看似相关的方法上设置“[STAThread]”。

有人知道我该如何解决这个错误吗?

4

1 回答 1

1

问题是,在第二种情况下,您的代码由 UI 线程调用,但在第一种情况下,我认为它是您的工作线程/通信线程之一。在 WPF 中,所有 UI 更改必须在 UI 线程中完成或使用特殊Dispatcher对象分派给它。

将您的 UI 更改包装到一个单独的方法中并用于Application.Current.Dispatcher.Invoke调用它。

这是关于此问题及其解决方案的更详细的文章:http ://blog.decarufel.net/2009/03/good-practice-to-use-dispatcher-in-wpf.html

于 2012-11-23T11:58:16.170 回答