无效的跨线程访问。错误

时间:2011-11-23 10:18:04

标签: c# multithreading silverlight c#-4.0 silverlight-4.0

我在silverlight中有一个网页表单。

在点击某个按钮的操作时,我想更新另一个控件,如图表,文本框等

在填充图表或文本框的同时,我需要显示一个忙碌的指标

  1. 忙碌指示符应首先显示在屏幕
  2. 中 图表值后面的
  3. 应该更新
  4. 图表值将反映在屏幕上
  5. 忙碌指示应隐藏
  6. 但问题是,当我尝试使用Thread时,我收到错误“无效的跨线程访问。”。当线程正在访问 UI控件。我试过的4个步骤如下。

    任何有价值的建议如何解决这个问题。

    步骤1 =>尝试线程

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Threading;
    using System.ComponentModel;
    using System.Windows.Threading;
    
    
    namespace SilverlightApplication2
    {
      public partial class MainPage : UserControl
        {
    
            public MainPage()
            {
                InitializeComponent();
    
    
    
            }
    
            private void test1()
            {
    
    
                for (int i = 1; i < 10000; i++)
                {
                    System.Diagnostics.Debug.WriteLine(i.ToString());
                }
            textbox1.Text="test";   //=> Throwing Error "Invalid cross-thread access."
                busyIndicator1.IsBusy = false;   //=> Throwing Error "Invalid cross-thread access."
            }
    
    
    
         private void button1_Click(object sender, RoutedEventArgs e)
             {
                 busyIndicator1.IsBusy = true;
    
                 Thread th1 = new Thread(test1);
                 th1.Start();
    
             }
    
        }
    }
    

    步骤2 =&gt;尝试过BackgroundWorker

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Threading;
    using System.ComponentModel;
    using System.Windows.Threading;
    
    
    namespace SilverlightApplication2
    {
      public partial class MainPage : UserControl
        {
    
            public MainPage()
            {
                InitializeComponent();
    
    
    
            }
    
            private void test1()
            {
    
    
                for (int i = 1; i < 10000; i++)
                {
                    System.Diagnostics.Debug.WriteLine(i.ToString());
                }
            textbox1.Text="test";   //=> Throwing Error "Invalid cross-thread access."
                busyIndicator1.IsBusy = false;   //=> Throwing Error "Invalid cross-thread access."
            }
    
    
    
         private void button1_Click(object sender, RoutedEventArgs e)
             {
                 busyIndicator1.IsBusy = true;
    
                var bw = new BackgroundWorker();
                bw.DoWork += (s, args) =>
                {
                    test1();  //Stuff that takes some time
                };
                bw.RunWorkerCompleted += (s, args) =>
                {
                    busyIndicator1.IsBusy = false;
                };
                bw.RunWorkerAsync();              
             }
    
        }
    }
    

    步骤3 =&gt;试图从

    后面的代码中引发一个事件
    public delegate void LinkToEventHandler();
    public static event LinkToEventHandler Evt;
    
     private void button1_Click(object sender, RoutedEventArgs e)
     {
         busyIndicator1.IsBusy = true;
    
         Evt += new LinkToEventHandler(this.test1);
         Evt();
     }
    
    
    
    private void test1()
    {
    
    
        for (int i = 1; i < 10000; i++)
        {
            System.Diagnostics.Debug.WriteLine(i.ToString());
        }
        textbox1.Text="test";   //=> Throwing Error "Invalid cross-thread access."
        busyIndicator1.IsBusy = false;   //=> Throwing Error "Invalid cross-thread access."
    }
    

    步骤4 =&gt;尝试绑定Busyindicator

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Threading;
    using System.ComponentModel;
    using System.Windows.Threading;
    
    
    namespace SilverlightApplication2
    {
        public partial class MainPage : INotifyPropertyChanged
        {
            public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
            public const string IsBusyPropertyName = "busyIndicator1";
            private bool _isBusy = false;
            public bool IsBusy
            {
                get
                {
                    return _isBusy;
                }
                set
                {
                    if (_isBusy != value)
                    {
                        _isBusy = value;
                        RaisePropertyChanged(IsBusyPropertyName);
                    }
                }
            }
    
            protected void RaisePropertyChanged(string propertyName)
            {
                System.ComponentModel.PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
                if ((propertyChanged != null))
                {
                    propertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
                }
            }
    
    
            private void button1_Click(object sender, RoutedEventArgs e)
            {
    
                IsBusy = true;
    
                test1();
    
                IsBusy=false;
    
            }
    
        }
    
    
        public partial class MainPage : UserControl
        {
    
            public MainPage()
            {
                InitializeComponent();
    
    
    
            }
    
    
            private void test1()
            {
    
    
                for (int i = 1; i < 10000; i++)
                {
                    System.Diagnostics.Debug.WriteLine(i.ToString());
                }
    
    
            }
    
    
    
        }
    }
    

    注意: - 我想要一个解决方案,它应该在Silverlight中以Web形式工作,而不是windows窗体

2 个答案:

答案 0 :(得分:3)

您收到此错误的原因是因为UI方法只能在UI(又称Dispatcher)线程上调用。要在另一个线程上执行UI操作时要解决此问题,您应该在主UI线程上调用该操作。 (见下文)

内联调用

// Disable some control
this.Dispatcher.BeginInvoke(new Action(() => this.SomeControl.IsEnabled = false));

方法驱动的调用

private void SomeMethodRunningOnAnotherThread()
{
    // ... perform some operations

    // Update the UI
    UpdateUI();

    // ... perform more operations
}

private void UpdateUI()
{
    // Make sure we're running on the UI thread
    if (!CheckAccess())
    {
        this.Dispatcher.BeginInvoke(new Action(UpdateUI));
        return;
    }

    // Disable some control
    this.SomeControl.IsEnabled = false;
}

在大多数情况下,第二种方法可能更好 - 特别是在执行多个UI操作时。值得注意的是,一旦UI线程变为空闲,这些UI操作将在UI线程上执行,因此如果您已经将其执行其他操作,则不会看到更新。此外,通过使用BeginInvoke,您不会占用调用线程。

答案 1 :(得分:2)

这对你有用。基本上将处理代码放在一个线程中,并通过Dispatcher

返回您的UI控件
 public partial class MainPage : UserControl
    {
        private Thread _thread1;

        public MainPage()
        {
            InitializeComponent();
        }

        private void StartThreads()
        {
            _thread1 = new Thread(test1);
            _thread1.Start();
        }
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            busyIndicator1.IsBusy = true;
            StartThreads();
        }

        private void test1()
        {
            for (int i = 1; i < 10000; i++)
            {
                System.Diagnostics.Debug.WriteLine(i.ToString());
            }
            this.Dispatcher.BeginInvoke(delegate()
            {
                textBox1.Text = "test";
                busyIndicator1.IsBusy = false;
            });
        }
    }