C# 跨线程使用引用对象

C# 跨线程使用引用对象,c#,multithreading,devexpress,pass-by-reference,C#,Multithreading,Devexpress,Pass By Reference,我所做的是创建一个对象(A),它包含对另一个对象(B)的引用。我的代码的UI部分将这些对象(A)保存在绑定列表中,该列表用作DevExpress网格视图的数据源。控制器通过事件将新创建的对象(A)发送到UI。控制器还有一个更新引用对象(B)的线程。引发的异常来自DevXPress GridView并读取“检测到跨线程操作。若要抑制此异常,请设置DevXPress.Data.CurrencyDataController.DisableThreadingProblemsDetection=true”

我所做的是创建一个对象(A),它包含对另一个对象(B)的引用。我的代码的UI部分将这些对象(A)保存在绑定列表中,该列表用作DevExpress网格视图的数据源。控制器通过事件将新创建的对象(A)发送到UI。控制器还有一个更新引用对象(B)的线程。引发的异常来自DevXPress GridView并读取“检测到跨线程操作。若要抑制此异常,请设置DevXPress.Data.CurrencyDataController.DisableThreadingProblemsDetection=true”

现在,我不想抑制此异常,因为代码最终将在关键应用程序中结束

那么,如何在不引起问题的情况下跨线程更新引用对象呢?下面是我的测试应用程序中的代码。在实际的程序中,它基本上是相同的

更新 用户界面中的错误已由Nicholas Butler的回答修复,但现在异常已转移到Employee类中。我已经更新了代码以反映这些更改

这是我的密码

*用户界面*

员工界面:

    class EmployeeController
{
    List<IEmployee> emps;
    Task empUpdater;
    CancellationToken cancelToken;
    CancellationTokenSource tokenSource;
    Pay payScale1;
    Pay payScale2;

    public EmployeeController()
    {
        payScale1 = new Pay(12.00, 10.00);
        payScale2 = new Pay(14.00, 11.00);
        emps = new List<IEmployee>();
    }

    public void Start()
    {
        empUpdater = new Task(AddEmployee, cancelToken);
        tokenSource = new CancellationTokenSource();
        cancelToken = tokenSource.Token;
        empUpdater.Start();
    }

    public bool Stop()
    {
        tokenSource.Cancel();
        while (!empUpdater.IsCompleted)
        { }
        return true;
    }

    private void AddEmployee()
    {
        IEmployee emp = new Employee("steve", ref payScale1);
        ThrowEmployeeEvent(emp);
        emps.Add(emp);
        emp = new Employee("bob", ref payScale2);
        ThrowEmployeeEvent(emp);
        emps.Add(emp);
        int x = 0;

        while (!cancelToken.IsCancellationRequested)
        {
            emp = new Employee("Emp" + x, ref payScale1);
            ThrowEmployeeEvent(emp);
            x++;
            emp = new Employee("Emp" + x, ref payScale2);
            ThrowEmployeeEvent(emp);

            Thread.Sleep(1000);

            payScale2.UpdatePay(10.0);
            payScale1.UpdatePay(11.0);

            Thread.Sleep(5000);
        }
    }

    private void ThrowEmployeeEvent(IEmployee emp)
    {
        if (onNewEmployee != null)
            onNewEmployee(emp);
    }

    public delegate void NewEmployee(IEmployee emp);
    public event NewEmployee onNewEmployee;
}
    interface IEmployee : INotifyPropertyChanged
{
    string Name { get; set; }
    double Salary { get;}
}
    class Pay : INotifyPropertyChanged
{
    private double _salary;
    private double _bonus;
    public double Salary { get { return _salary; } set { _salary = value; if(PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("Salary"));} }
    public double Bonus { get { return _bonus; } set { _bonus = value; if (PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("Bonus")); } }

    public Pay(double salary, double bonus)
    {
        Salary = salary;
        Bonus = bonus;
    }

    public void UpdatePay(double salary)
    {
        Salary += salary;
        if (onChange != null)
            this.onChange();
    }

    public void UpdatePay(double salary, double bonus)
    {
        Salary += salary;
        Bonus += bonus;

        if (onChange != null)
            this.onChange();
    }

    public delegate void Change();
    public event Change onChange;

    public event PropertyChangedEventHandler PropertyChanged;
}
薪资等级:

    class EmployeeController
{
    List<IEmployee> emps;
    Task empUpdater;
    CancellationToken cancelToken;
    CancellationTokenSource tokenSource;
    Pay payScale1;
    Pay payScale2;

    public EmployeeController()
    {
        payScale1 = new Pay(12.00, 10.00);
        payScale2 = new Pay(14.00, 11.00);
        emps = new List<IEmployee>();
    }

    public void Start()
    {
        empUpdater = new Task(AddEmployee, cancelToken);
        tokenSource = new CancellationTokenSource();
        cancelToken = tokenSource.Token;
        empUpdater.Start();
    }

    public bool Stop()
    {
        tokenSource.Cancel();
        while (!empUpdater.IsCompleted)
        { }
        return true;
    }

    private void AddEmployee()
    {
        IEmployee emp = new Employee("steve", ref payScale1);
        ThrowEmployeeEvent(emp);
        emps.Add(emp);
        emp = new Employee("bob", ref payScale2);
        ThrowEmployeeEvent(emp);
        emps.Add(emp);
        int x = 0;

        while (!cancelToken.IsCancellationRequested)
        {
            emp = new Employee("Emp" + x, ref payScale1);
            ThrowEmployeeEvent(emp);
            x++;
            emp = new Employee("Emp" + x, ref payScale2);
            ThrowEmployeeEvent(emp);

            Thread.Sleep(1000);

            payScale2.UpdatePay(10.0);
            payScale1.UpdatePay(11.0);

            Thread.Sleep(5000);
        }
    }

    private void ThrowEmployeeEvent(IEmployee emp)
    {
        if (onNewEmployee != null)
            onNewEmployee(emp);
    }

    public delegate void NewEmployee(IEmployee emp);
    public event NewEmployee onNewEmployee;
}
    interface IEmployee : INotifyPropertyChanged
{
    string Name { get; set; }
    double Salary { get;}
}
    class Pay : INotifyPropertyChanged
{
    private double _salary;
    private double _bonus;
    public double Salary { get { return _salary; } set { _salary = value; if(PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("Salary"));} }
    public double Bonus { get { return _bonus; } set { _bonus = value; if (PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("Bonus")); } }

    public Pay(double salary, double bonus)
    {
        Salary = salary;
        Bonus = bonus;
    }

    public void UpdatePay(double salary)
    {
        Salary += salary;
        if (onChange != null)
            this.onChange();
    }

    public void UpdatePay(double salary, double bonus)
    {
        Salary += salary;
        Bonus += bonus;

        if (onChange != null)
            this.onChange();
    }

    public delegate void Change();
    public event Change onChange;

    public event PropertyChangedEventHandler PropertyChanged;
}

我非常感谢任何帮助

您正在调用
empList.Add(emp)即使在
invokererequired==true
时也是如此。尝试:

private void AddEmployee(IEmployee empl)
{
    if (InvokeRequired)
    {
        this.Invoke(new AddEmployeInvoke(AddEmployee), new Object[] {empl});
    }
    else
    {
        empList.Add(empl); //exception thrown here
    }
}

您还需要在UI线程上引发
INotifyPropertyChanged
事件,但您没有可调用
Invoke
的UI控件。实现这一点的简单方法是存储对主窗体的引用,并将其设置为公共静态

public partial class Form1 : Form
{
    public static Control UI { get; private set; }

    public Form1()
    {
        UI = this;
    }
}
然后,您可以在应用程序中的任何位置使用
Form1.UI.invokererequired
Form1.UI.Invoke


我试图一步一个脚印,但如果您想要更正确的解决方案,可以将UI
SynchronizationContext
传递给控制器,并使用其
Post
Send
方法:

public Form1()
{
    controller = new EmployeeController( SynchronizationContext.Current );
    ...

class EmployeeController
{
    private SynchronizationContext _SynchronizationContext = null;

    public EmployeeController( SynchronizationContext sc )
    {
        _SynchronizationContext = sc;
        ...
然后你必须把它放到你的物体上。要引发事件,您需要执行以下操作:

var evt = this.PropertyChanged;
if ( evt != null ) sc.Send(
    new SendOrPostCallback( state => evt( this, ...EventArgs... ) ),
    null );

问题是,
EmployeeController.onneweemployee
正在非UI线程上启动。使用基于事件的异步模式在特定(在本例中为UI)线程上引发事件:


或者,您可以在每个事件处理程序中检查IsInvokeRequired,如果是,则使用.Invoke返回UI线程。。这更麻烦,但在您的情况下可能更容易/更快地实现。

Ahh这在我的Employee类中的方法“\u myPay\u PropertyChanged()”This.PropertyChanged(This,new PropertyChangedEventArgs(“Salary”);正在引发相同的异常。我是否还需要对其调用?或者您可以在EmployeeController中实现基于事件的异步模型,而不必执行任何操作,因为EmployeeController将负责对righe线程进行调用。需要更多的时间来理解,但这是一个更简洁的解决方案。这不会打破松耦合规则吗?如果我的所有INotifyPropertyChanged类都需要了解UI类,而如果更改正确,则需要进行大量更改?请阅读我答案中的MSDN链接。EmployeeController不需要知道UI类就可以使用EBAP将事件调用打包回给定线程。线程和对象实例是两个完全不同的东西。很抱歉让Myles感到困惑,但我之前的回答是针对Nicholas的。因为必须检查我的代码并将Form1.UI.invokererequired放入其中会引起麻烦。我一直在读你发布的链接,试图弄清楚它。