C# WPF解决“调用线程无法访问此对象,因为另一个线程拥有该对象”

本文介绍了一种在WPF应用程序中使用后台线程结合Dispatcher实现按钮状态实时更新的方法,解决了因主线程阻塞导致的界面响应问题。

本意,是想用变量来控制按钮的IsEnable,但是发现要么没法实时控制,要么报错:调用线程无法访问此对象,因为另一个线程拥有该对象

后来问了领导,领导说要用dispatcher,查了下英语单词是n,调度员;[计] 调度程序;[计] 分配器

意思,话不多说直接上代码:

  private void Window_Loaded(object sender, RoutedEventArgs e)
        {

Thread thread = new Thread(SampletubeButtonStateSet);//20221114新开后台线程
            thread.IsBackground = true;
            thread.Priority = ThreadPriority.Lowest;
            thread.Start();

      }

 public void SampletubeButtonStateSet()
        {
            while (true) //将要实时刷新的代码放在while去实时扫描
            {
                App.Current.Dispatcher.BeginInvoke((System.Action)(() =>    //用这个方法给它实时刷新
                {
                    if (GlobalPara.Isrunning == true)
                    {
                        this.试管切换.IsEnabled = false;
                    }
                    else
                    {
                        this.试管切换.IsEnabled = true;
                    }
                }));
               Thread.Sleep(10);
              
            }             
                   
           
        }           

C# WPF 应用程序中,当遇到“InvalidOperationException: 调用线程无法访问对象,因为一个线程拥有对象”错误时,通常是由于尝试从非 UI 线程(如 Task 或 Thread)打开或更新窗体,而 WPF 的 UI 元素不是线程安全的,只有创建窗体的线程(通常是主 UI 线程)才能安全地访问和修改这些元素[^2]。以下是解决该问题的方法: ### 使用 Dispatcher.Invoke 方法 可以利用委托机制,子线程向主线程发起一个委托,由主线程触发相关动作来完成操作。示例代码如下: ```csharp // 委托 lb.Dispatcher.Invoke(new Action( delegate { // ------- 需要完成什么操作,写在这里就可以了, 主线程会触发该Action来完成------- lb.Content = "666"; }) ); ``` 以下是一个示例,将引发问题的代码放入 `Dispatcher.Invoke` 中: ```csharp Dispatcher.Invoke( new Action(() => { // 将引发问题的代码放入此处 // 便可解决此问题 textblock.Text = i.ToString() + "秒后退出"; }) ); ``` ### 代码实战示例 ```csharp public static Action Login_Action; // 声明事件 public Timer timer; // 计时器声明 public WinVM() { // 事件触发绑定的方法 Login_Action += TimerLogin; timer = new Timer(new TimerCallback(Execute), null, 2000, 10000); } // 创建回调触发方法 public static void Execute(object o) { Login_Action?.Invoke(); } /// <summary> /// 需要定时执行的方法 /// </summary> public static void TimerLogin() { if (CommWithPCs.Instance.globalReLoginFlag) { long EmptyTime = GetLastInputTime(); if (EmptyTime > 10 * 1000) { Window1 win = Window1.Instance; // 利用 Dispatcher.Invoke 让主线程操作 UI win.passwordBox.Dispatcher.Invoke(new Action( delegate { win.passwordBox.Password = ""; }) ); win.Dispatcher.Invoke(new Action( delegate { win.frm_MainPage.Navigate(null); }) ); } } } ``` ### 委托刷新 UI 线程示例 ```csharp using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; namespace 委托刷新UI线程 { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { private delegate void UpdateUIDelegate(); public MainWindow() { InitializeComponent(); UpdateUIThreadTest(); } private void UpdateUIThreadTest() { var th = new Thread(ThreadUpdateUI); th.Start(); } private void ThreadUpdateUI() { UpdateUIDelegate updateUIDelegate = new UpdateUIDelegate(UpdateUI); this.Dispatcher.Invoke(updateUIDelegate); } private void UpdateUI() { textBox.Text = "Refreshed."; } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值