Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/257.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# BindingList通过控制器绑定到网格数据源,然后从另一个线程跨线程异常更新_C#_Winforms_Model View Controller_Bindinglist - Fatal编程技术网

C# BindingList通过控制器绑定到网格数据源,然后从另一个线程跨线程异常更新

C# BindingList通过控制器绑定到网格数据源,然后从另一个线程跨线程异常更新,c#,winforms,model-view-controller,bindinglist,C#,Winforms,Model View Controller,Bindinglist,去年我一直在研究JavaScript和Angular,目前正在Winforms中进行一个项目。我理解UI控件InvokeRequired的跨线程问题,但我以前没有使用BindingList,所以为了进行实验,我有一个基本的应用程序,它有一个表单、控制器和实现INotifyPropertyChanged的POCO。表单被注入控制器,控制器有一个绑定列表。为了模拟处理数据的外部线程,我在控制器内部有一个Start方法,它创建一个线程,运行一个循环并更新库存列表。显然,这将引发属性更改事件,该事件将通

去年我一直在研究JavaScript和Angular,目前正在Winforms中进行一个项目。我理解UI控件InvokeRequired的跨线程问题,但我以前没有使用BindingList,所以为了进行实验,我有一个基本的应用程序,它有一个表单、控制器和实现INotifyPropertyChanged的POCO。表单被注入控制器,控制器有一个绑定列表。为了模拟处理数据的外部线程,我在控制器内部有一个Start方法,它创建一个线程,运行一个循环并更新库存列表。显然,这将引发属性更改事件,该事件将通知网格及其数据源,但是我得到了跨线程异常。我想知道的是,这方面的常见做法是什么?我过去的经验是从GUI后台工作程序启动线程,因此代码通常已经在表单中,并且可以访问“this”来调用所需的invoker。但是,当从控制器使用BindingList时,我没有这样的功能

Form1控制器

从属对象


假设这是我应该要求的,我如何将更改的属性从BindingList封送回UI线程?

我根据您的代码构建了一个示例,但没有收到跨线程异常;股票正在更新中。你确定你的问题是绑定列表吗?谢谢你这么快回答。我意识到我忘了提到我正在使用DevExpress。键入该注释后,我使用WinForms datagridview,它工作正常,但如果我使用DevXPress XtraGrid,则会出现x线程异常:在DevXPress.Data.v13.2.dll中出现“System.InvalidOperationException”类型的未处理异常。其他信息:检测到跨线程操作。要抑制此异常,请设置DevExpress.Data.CurrencyDataController.DisableThreadingProblemsDetection=true。我将尝试使用该标志集,看看会发生什么情况。OK,我也可以使用DevExpress网格进行尝试。在没有实际查看的情况下,我关心的是设置该标志可能会使它吞下异常,而不是实际处理跨线程问题。但是值得一试。确定设置DevExpress异常中的属性意味着DevExpress网格现在可以工作。然而,这和使用普通winforms网格不应该引发线程异常吗,因为属性更改发生在我在控制器中生成的线程中?这只是一个假设,因为我没有做任何修补,但我猜,它们附加到BindingList的ListChanged事件的事件处理程序在开始时调用了所需的检查;Windows网格可能内置了它,而DevExpress网格显然有一个用于打开和关闭它的属性,因为DX具有所有属性。
public class Form1Controller
{
    public bool IsRunning { get; private set; }

    private readonly Random _Random = new Random();

    public Form1Controller()
    {
        Stocks = new BindingList<Stock>();           
        Stocks.Add(new Stock()
        {
            Name = "Microsoft",
            Ticker = "MSFT",
            Price = 25,
            Volume = 100000,
            LastTraded = DateTime.Now
        });
        Stocks.Add(new Stock()
        {
            Name = "Google",
            Ticker = "GOOG",
            Price = 450,
            Volume = 100000,
            LastTraded = DateTime.Now
        });
        Stocks.Add(new Stock()
        {
            Name = "Apple",
            Ticker = "AAPL",
            Price = 750,
            Volume = 100000,
            LastTraded = DateTime.Now
        });
        Stocks.Add(new Stock()
        {
            Name = "Oracle",
            Ticker = "ORCL",
            Price = 80,
            Volume = 100000,
            LastTraded = DateTime.Now
        });
    }

    public BindingList<Stock> Stocks { get; set; }

    public void Start()
    {
        IsRunning = true;

        new Thread(() => 
        {
            while (IsRunning)
            {
                var index = _Random.Next(0, Stocks.Count);

                Debug.WriteLine(index);

                var stock = Stocks[index];
                stock.Price += 1;
                stock.Volume += 500;
                stock.LastTraded = DateTime.Now;

                Thread.Sleep(100);
            }                
        }).Start();            
    }

    public void Stop()
    {
        IsRunning = false;
    }
}
public class Stock : DependencyObject
{        
    private string name;
    public string Name
    {
        get { return name; }
        set { SetField(ref name, value, () => Name); }
    }

    private string ticker;
    public string Ticker
    {
        get { return ticker; }
        set { SetField(ref ticker, value, () => Ticker); }
    }

    private int price;
    public int Price
    {
        get { return price; }
        set { SetField(ref price, value, () => Price); }
    }

    private long volume;
    public long Volume
    {
        get { return volume; }
        set { SetField(ref volume, value, () => Volume); }
    }

    private DateTime lastTraded;
    public DateTime LastTraded
    {
        get { return lastTraded; }
        set { SetField(ref lastTraded, value, () => LastTraded); }
    }   
}
public class DependencyObject : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) 
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    protected bool SetField<T>(ref T field, T value, string propertyName)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }

    protected virtual void OnPropertyChanged<T>(Expression<Func<T>> selectorExpression)
    {
        if (selectorExpression == null)
            throw new ArgumentNullException("selectorExpression");
        MemberExpression body = selectorExpression.Body as MemberExpression;
        if (body == null)
            throw new ArgumentException("The body must be a member expression");
        OnPropertyChanged(body.Member.Name);
    }

    protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(selectorExpression);
        return true;
    }
}
public partial class Form1 : Form
{        
    private readonly Form1Controller _Controller = new Form1Controller();

    public Form1(Form1Controller controller)
    {
        InitializeComponent();

        _Controller = controller;
        _MainGrid.DataSource = _Controller.Stocks;
    }

    private void _StartButton_Click(object sender, EventArgs e)
    {
        _Controller.Start();
    }

    private void _StopButton_Click(object sender, EventArgs e)
    {
        _Controller.Stop();
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
        _Controller.Stop();
    }
}