Use reference object by streams

What I am doing is creating an object (A) that contains a link to another object (B). The UI part of my code contains these objects (A) in a BindingList, which is used as a data source to represent the DevExpress grid. The controller sends the newly created objects (A) to the user interface through the event. The controller also has a thread that updates the specified object (B). The exception is thrown from the DevExpress GridView and reads "Crossflow operation detected. To suppress this exception, set DevExpress.Data.CurrencyDataController.DisableThreadingProblemsDetection = true".

Now I do not want to suppress this exception, because ultimately the code will end up in a critical application.

So, how can I update the reference object in streams without causing problems? Here is the code from my test application. In a real program, it will be almost the same.

UPDATE The error in the user interface was fixed by Nicholas Butler's answer, but now the exception has moved to the Employee class. I updated the code to reflect the changes.

Here is my code

* UI *

    public partial class Form1 : Form
{
    private BindingList<IEmployee> empList;
    EmployeeController controller;
    private delegate void AddEmployeInvoke(IEmployee employee);
    public Form1()
    {
        controller = new EmployeeController();
        controller.onNewEmployee += new EmployeeController.NewEmployee(controller_onNewEmployee);
        empList = new BindingList<IEmployee>();
        InitializeComponent();
    }

    void controller_onNewEmployee(IEmployee emp)
    {
        AddEmployee(emp);
    }

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

    private void Form1_Load(object sender, EventArgs e)
    {
        this.gridControl1.DataSource = empList;
        this.gridControl1.RefreshDataSource();
        controller.Start();
    }
 }

Controller:

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

Employee Class: (Exception thrown in this class)

    class Employee : IEmployee
{
    private string _name;
    private double _salary;
    private Pay _myPay;
    public string Name 
    { 
        get { return _name; } 
        set { _name = value; 
            //if (PropertyChanged != null) this.PropertyChanged(this, new PropertyChangedEventArgs("Name")); 
            } 
    }        
    public double Salary
    {
        get { return _salary; }
    }
    int x = 1;

    public Employee(string name, ref Pay pay)
    {
        _myPay = pay;
       _myPay.PropertyChanged += new PropertyChangedEventHandler(_myPay_PropertyChanged);
       _salary = _myPay.Salary;
        Name = name;
    }

    void _myPay_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "Salary")
        {
            _salary = _myPay.Salary;
            if (this.PropertyChanged != null)
                // exception thrown on the line below
                this.PropertyChanged(this, new PropertyChangedEventArgs("Salary"));
        }
    }

    public void ChangeName()
    {
        Name = "Me " + x;
        x++;
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Employee Interface:

    interface IEmployee : INotifyPropertyChanged
{
    string Name { get; set; }
    double Salary { get;}
}

Payment Class:

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

I really appreciate any help.

+5
source share
2 answers

, EmployeeController.onNewEmployee , UI. async , ( UI): http://msdn.microsoft.com/en-us/library/hkasytyf.aspx.

IsInvokeRequired , .Invoke, . , / .

+2

empList.Add(empl); InvokeRequired == true. :

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

INotifyPropertyChanged , UI Invoke on. - public static:

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

    public Form1()
    {
        UI = this;
    }
}

Form1.UI.InvokeRequired 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 );
+1

All Articles