简体   繁体   English

访问不同线程中的对象

[英]Access object in a different thread

Setup: 设定:

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

Level: 水平:

Beginner/Intermediate/new to threading 初学者/中级/线程新手

Objective: 目的:

1: A selenium web automation class that is triggered by a timer class so that the web automation class can exchange data with a javascript site at specific times. 1:由计时器类触发的Selenium Web自动化类,以便Web自动化类可以在特定时间与javascript站点交换数据。

2: Should be possible to migrate solution from WebForms to .NET library (dll). 2:应该可以将解决方案从WebForms迁移到.NET库(dll)。

Problem: 问题:

Step 1. Timer class sends time event to method in Web class to login to internet site = working. 步骤1.计时器类将时间事件发送到Web类中的方法以登录Internet站点=工作。

Step 2. Web automation class (WinForms/GUI) tries to retrieve data from the method that is triggered by timer class event = Exception: "Calling thread cannot access this object because a different thread owns it." 步骤2. Web自动化类(WinForms / GUI)尝试从计时器类event = event触发的方法中检索数据:异常:“调用线程无法访问该对象,因为另一个线程拥有它。” (as translated from swe). (从swe翻译而来)。

I admit I´m confused by the terminology in the area of threading that is new to me. 我承认我对新的线程领域的术语感到困惑。 Also, I understand some multithreading techniques are only valid for WinForms. 另外,我了解一些多线程技术仅对WinForms有效。 Since my objective is to migrate the solution to a dll these are not an option for me. 由于我的目标是将解决方案迁移到dll,因此这些都不是我的选择。 I´ve played around with Invoke(), but as I understand it´s limited to use in WinForms. 我玩过Invoke(),但是据我所知,它只能在WinForms中使用。 Guidance is highly appreciated! 指导受到高度赞赏!

WEB AUTOMATION CLASS: 网络自动化课程:

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

TIMER CLASS: 计时器类:

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

} }

When you want to update View's control from another Thread it must show you error. 当您想从另一个Thread更新View的控件时,它必须显示错误。 Because it is using by UI Thread. 因为它是通过UI Thread使用的。 In this case you have to use SynchronizationContext class or you can send Delegate to the App.Current.Dispatcher.BeginInvoke(delegate must be here) ; 在这种情况下,您必须使用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),

    //...
}

Alternative of SynchronizationContext : SynchronizationContext的替代方法:

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

      App.Current.Dispatcher.BeginInvoke(action);

    //...
}

Both of them are same. 他们都是一样的。

UI thread adapted for keyboard event and mouse event. 适用于键盘事件和鼠标事件的UI线程。 When you App.Current.Dispatcher.BeginInvoke(delegate) you say to the UI Thread that "execute this too". 当您App.Current.Dispatcher.BeginInvoke(delegate)您对“也执行此操作”的UI Thread说。

In addition you can suppose UI Thread like this 另外,您可以假设这样的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

}

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

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

This solution is probably only valid in my case. 该解决方案可能仅对我而言有效。 OP can delete this question if it´s believed to be a duplicate. 如果认为重复,OP可以删除该问题。

The first objective with was an easy to develop/run/debug situation with a GUI. 第一个目标是使用GUI轻松开发/运行/调试情况。 Setting properties causes no cross thread exception. 设置属性不会导致跨线程异常。 Showing the properties in a MessageBox.Show() causes no exception either. 在MessageBox.Show()中显示属性也不会引起异常。 Hence no cross thread issues to dodge in the development/GUI stage. 因此,在开发/ GUI阶段无需交叉线程问题。

The second objective was to migrate to a dll, hence no need to interfere with a GUI thread. 第二个目标是迁移到dll,因此无需干扰GUI线程。

/Thanks anyway /不管怎么说,还是要谢谢你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从不同的线程访问对象 - access object from a different thread 调用线程无法访问此对象,因为其他线程拥有 - The calling thread cannot access this object because a different thread owns 调用线程无法访问该对象,因为其他线程拥有它 - The calling thread cannot access this object because a different thread owns it 调用线程无法访问该对象,因为其他线程拥有它错误 - The calling thread cannot access this object because a different thread owns it error 调用线程无法访问此对象,因为另一个线程拥有它 - The calling thread cannot access this object because a different thread owns it 调用线程无法访问此对象,因为另一个线程拥有它“异常” - The calling thread cannot access this object because a different thread owns it “exception” WPF:调用线程无法访问此对象,因为其他线程拥有它 - WPF: The calling thread cannot access this object because a different thread owns it 调用线程无法访问该对象,因为其他线程拥有它 - The calling thread can not access this object because a different thread owns it WPF线程和GUI如何从不同的线程访问对象? - WPF thread and GUI how to access object from different thread? 调用线程无法访问此 object,因为不同的线程拥有它 - The calling thread cannot access this object because a different thread owns it
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM