Quello che sto facendo è creare un oggetto (A) che contiene un riferimento a un altro oggetto (B). La parte dell'interfaccia utente del mio codice contiene quegli oggetti (A) in un BindingList che viene utilizzato come origine dati per una vista griglia DevExpress. Il controller invia gli oggetti appena creati (A) all'interfaccia utente tramite un evento. Il controller ha anche una discussione che aggiorna l'oggetto di riferimento (B). L'eccezione generata da DevExpress GridView e legge "Operazione cross thread rilevata. Per sopprimere questa eccezione, impostare DevExpress.Data.CurrencyDataController.DisableThreadingProblemsDetection = true".Utilizzare un oggetto di riferimento attraverso i thread
Ora non voglio sopprimere questa eccezione perché il codice finirà per finire in un'applicazione critica.
Quindi, come posso aggiornare un oggetto di riferimento attraverso i thread senza causare problemi? Ecco il codice dalla mia applicazione di test. Sarà essenzialmente lo stesso nel programma attuale.
UPDATE L'errore nell'interfaccia utente è stato fissato dalla risposta da Nicholas Butler, ma ora l'eccezione si è spostato nella classe Employee. Ho aggiornato il codice per riflettere le modifiche.
Ecco il mio codice
* 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;
}
classe Employee: (Eccezione generata in questa classe)
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;
}
interfaccia dei dipendenti:
interface IEmployee : INotifyPropertyChanged
{
string Name { get; set; }
double Salary { get;}
}
Pay Classe:
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;
}
apprezzo molto di aiuto.
Ah che ha funzionato ma ora nella mia classe Employee con il metodo "_myPay_PropertyChanged()" this.PropertyChanged (this, new PropertyChangedEventArgs ("Salary")); sta lanciando la stessa eccezione. Devo anche chiamare un invoke su questo? – Stephen
Sì, ho aggiornato la mia risposta. –
Oppure potresti implementare il modello asincrono basato su evento nel tuo EmployeeController e non dovresti fare nulla di tutto ciò in quanto EmployeeController sarebbe responsabile di effettuare le chiamate sul thread delle righe. Prende un po 'più tempo per capire, ma una soluzione molto più ordinata. –