无效的跨线程访问。错误

发布于 2024-12-17 20:22:29 字数 5631 浏览 0 评论 0原文

我有一个 silverlight 网络表单。

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

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

  1. 繁忙指示器应首先显示在屏幕上,
  2. 图表值后面应该显示更新
  3. 图表值将反映在屏幕上
  4. 忙碌指示器应该隐藏

但问题是当我尝试使用线程时我收到错误“无效的跨线程访问”。当线程访问时 用户界面控件。我尝试过的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 =>尝试了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 => 后面的代码引发事件

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 => 尝试绑定 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 形式工作的解决方案

I have a web form in silverlight.

On action of some button click i want to update a another control like chart, Textbox etc

In the mean time when it fills the chart or textbox, i need to show a busy indicator

  1. Busy indicator should show first in screen
  2. behind the chart value should get update
  3. Chart value will reflect in screen
  4. Busy indicator should hide

But the problem is when i try using Thread I am getting an error "Invalid cross-thread access.". As the thread is accessing
the UI control. The 4 steps which i have tried is as follows.

Any valuable suggestion how to solve this issue.

Step 1 => Tried Thread

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

         }

    }
}

step 2 => Tried 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();              
         }

    }
}

Step 3 => Tried to raise an Event from the code behind

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."
}

step 4 => Tried Binding the 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());
            }


        }



    }
}

Note:- I want a solution which should work in Web form in silverlight not the windows form

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

不回头走下去 2024-12-24 20:22:30

您收到此错误的原因是 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,您不会阻塞调用线程。

The reason you are getting this error is because UI methods can only be invoked on the UI (aka Dispatcher) thread. To overcome this when wanting to perform UI operations on another thread, you should invoke the action on the main UI thread. (See below)

Inline Invocation

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

Method-Driven Invocation

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

In most cases, the second approach may be better - particularly when performing multiple UI operations. It is worth noting that these UI actions will be executed on the UI thread once the UI thread has become idle, so if your already holding it up doing something else, you won't see the update. Also, by using BeginInvoke you don't hold up the calling thread.

恬淡成诗 2024-12-24 20:22:30

这应该对你有用。本质上是将您的处理代码放在一个线程中,并通过调度程序取回您的 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;
            });
        }
    }

This should work for you. Essentially place your processing code in a thread and get back your UI control via a Dispatcher

 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;
            });
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文