访问不同线程中的对象

时间:2019-06-26 11:15:06

标签: c# .net multithreading

设置:

Win10 .NET 4.7.1 / VS2017 .NET 4.5 / C#

级别:

初学者/中级/线程新手

目标:

1:由计时器类触发的硒Web自动化类,以便Web自动化类可以在特定时间与javascript网站交换数据。

2:应该可以将解决方案从WebForms迁移到.NET库(dll)。

问题:

步骤1。计时器类将时间事件发送到Web类中的方法以登录到Internet站点=工作。

步骤2。Web自动化类(WinForms / GUI)尝试从计时器类event =异常触发的方法中检索数据:异常:“由于其他线程拥有该对象,因此调用线程无法访问该对象。” (从swe翻译而来)。

我承认我对我来说是新的线程领域的术语感到困惑。另外,我了解一些多线程技术仅对WinForms有效。由于我的目标是将解决方案迁移到dll,因此这些都不是我的选择。我玩过Invoke(),但是据我所知,它只能在WinForms中使用。指导受到高度赞赏!

网络自动化课程:

    private EdgeDriver driver;
    private SeleniumHelper helper;
    private WebAutomationTimer timer;
    private double account;

    public double Account { get => this.account; set => this.account = value; }

    public Form1()
    {
        InitializeComponent();
        timer = new WebAutomationTimer(02, 36, 00, 02, 38, 00);
        timer.OnLoginTime += Timer_OnLoginTime;
        timer.OnLogoutTime += Timer_OnLogoutTime;
    }

    private void Timer_OnLoginTime()
    {
        Login();
    }

    private void Timer_OnLogoutTime()
    {
        Logout();
    }

    public bool Login()
    {
        try
        {
            // working login code

    UpdateLabels();
        }
        catch (Exception e)
        {

        }
    }

    private void UpdateLabels()
    {
        // EXCEPTION !!!
        lblAccount.Text = GetAccount(); 
    // EXCEPTION !!!
    }

计时器类:

class WebAutomationTimer
{
    public event TimerEvent OnLoginTime;
    public event TimerEvent OnLogoutTime;
    //public event TimerEvent OnSecond;
    private System.Timers.Timer timer;
    private DateTime now;
    private int loginHour;
    private int loginMin;
    private int loginSec;
    private int logoutHour;
    private int logoutMin;
    private int logoutSec;

    public WebAutomationTimer(int loginHour, int loginMin, int loginSec, int logoutHour, int logoutMin, int logoutSec)
    {
        timer = new System.Timers.Timer();
        timer.Interval = 1000; // 1 sec
        timer.Elapsed += Timer_Elapsed;
        timer.Start();
        this.loginHour = loginHour;
        this.loginMin = loginMin;
        this.loginSec = loginSec;
        this.logoutHour = logoutHour;
        this.logoutMin = logoutMin;
        this.logoutSec = logoutSec;
    }

    // Each second event
    private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        now = DateTime.Now;
        //OnSecond();

        //login
        if (now.Hour == loginHour && now.Minute == loginMin && now.Second == loginSec)
            OnLoginTime();

        //logout
        if (now.Hour == logoutHour && now.Minute == logoutMin && now.Second == logoutSec)
            OnLogoutTime();
    }
}

}

3 个答案:

答案 0 :(得分:1)

当您要从另一个Thread更新View的控件时,它必须显示错误。因为它是通过UI Thread使用的。在这种情况下,您必须使用SynchronizationContext类,或者可以将Delegate发送到App.Current.Dispatcher.BeginInvoke(delegate must be here);

SynchronizationContext _context = SynchronizationContext.Current;

private void UpdateLabels()
{
        _context.Post(x=> 
             {
                lblAccount.Text = AccountBalance.ToString();
             },null),

    //...
}

SynchronizationContext的替代方法:

private void UpdateLabels()
{
      var action = new Action(() => 
      {
              lblAccount.Text = AccountBalance.ToString();
      });

      App.Current.Dispatcher.BeginInvoke(action);

    //...
}

他们都是一样的。

适用于键盘事件和鼠标事件的UI线程。 当您App.Current.Dispatcher.BeginInvoke(delegate)时,您对UI Thread说 “也执行这个”。

此外,您可以假设UI Thread这样

while(!thisApplication.Ended)
{
    wait for something to appear  in message queue
    Got something : what kind of this message? 
    Keyboard/Mouse message --> fire event handler 
    User BeginInvoke message --> execute delegate
    User Invoke message --> execute delegate & post result

}

答案 1 :(得分:0)

此错误是因为更改标签文本,因为标签在另一个线程中,您可以使用此代码

 lblAccount.Invoke(new EventHandler((s, ee) => { lblAccount.Text = AccountBalance.ToString(); }));

答案 2 :(得分:0)

此解决方案可能仅对我而言有效。如果认为重复,OP可以删除该问题。

第一个目标是使用GUI轻松开发/运行/调试情况。设置属性不会导致跨线程异常。在MessageBox.Show()中显示属性也不会引起异常。因此,在开发/ GUI阶段无需回避任何跨线程问题。

第二个目标是迁移到dll,因此无需干扰GUI线程。

/仍然感谢