C# 绑定、线程和winforms

C# 绑定、线程和winforms,c#,winforms,multithreading,C#,Winforms,Multithreading,如何将ProgressBar绑定到在另一个线程中更新的类的属性 下面的代码示例显示了我的第一次天真尝试。它不起作用,因为我得到了关于跨线程通信的运行时错误。我认为我需要以某种方式使用Invoke,但我不确定如何使用Binding类 using System; using System.Drawing; using System.Windows.Forms; using System.ComponentModel; using System.Threading; class ProgressFo

如何将ProgressBar绑定到在另一个线程中更新的类的属性

下面的代码示例显示了我的第一次天真尝试。它不起作用,因为我得到了关于跨线程通信的运行时错误。我认为我需要以某种方式使用Invoke,但我不确定如何使用Binding类

using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using System.Threading;

class ProgressForm : Form
{
    private ProgressBar pbProgress;

    public ProgressForm(ref LongOp lo)
    {
        Binding b = new Binding("Value", lo, "Progress");
        pbProgress = new ProgressBar();
        pbProgress.DataBindings.Add(b);
        this.Controls.Add(pbProgress);
    }
}

class Program : Form
{
    private Button btnStart;
    private LongOp lo;

    public Program()
    {
        lo = new LongOp();
        btnStart = new Button();

        btnStart.Text = "Start long operation";
        btnStart.Click += new EventHandler(btnStart_Click);

        this.Controls.Add(btnStart);
    }

    private void btnStart_Click(object sender, EventArgs e)
    {
        ProgressForm pf = new ProgressForm(ref lo);
        lo.DoLongOp();
        pf.ShowDialog();
    }

    [STAThread]
    public static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Program());
    }
}

class LongOp : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    private int progress;

    public void DoLongOp()
    {
        Thread thread = new Thread(new ThreadStart(this.run));
        thread.Start();
    }

    public void run()
    {
        for (int i = 0; i < 10; ++i)
        {
            Thread.Sleep(1000);
            Progress++;
        }
    }

    public int Progress
    {
        get
        {
            return progress;
        }

        set
        {
            progress = value;
            NotifyPropertyChanged("Progress");
        }
    }

    private void NotifyPropertyChanged(String field)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(field));
        }
    }
}
使用系统;
使用系统图;
使用System.Windows.Forms;
使用系统组件模型;
使用系统线程;
班级进度表:表格
{
私人进度计划;
公共进度表(参考LongOp lo)
{
绑定b=新绑定(“值”,lo,“进度”);
pbProgress=newprogressbar();
pbProgress.DataBindings.Add(b);
this.Controls.Add(pbProgress);
}
}
课程名称:表格
{
私人按钮btnStart;
私人朗格普洛;
公共计划()
{
lo=新的LongOp();
btnStart=新建按钮();
btnStart.Text=“开始长时间操作”;
btnStart.Click+=新建事件处理程序(btnStart\u Click);
this.Controls.Add(btnStart);
}
私有void btnStart_单击(对象发送方,事件参数e)
{
ProgressForm pf=新的ProgressForm(参考lo);
lo.DoLongOp();
pf.ShowDialog();
}
[状态线程]
公共静态void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
运行(新程序());
}
}
LongOp类:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
私人投资进展;
公共空间
{
线程线程=新线程(新线程开始(this.run));
thread.Start();
}
公开募捐
{
对于(int i=0;i<10;++i)
{
睡眠(1000);
进步++;
}
}
公共信息技术进步
{
得到
{
返回进度;
}
设置
{
进步=价值;
NotifyPropertyChanged(“进度”);
}
}
私有void NotifyPropertyChanged(字符串字段)
{
if(PropertyChanged!=null)
{
PropertyChanged(此,新PropertyChangedEventArgs(字段));
}
}
}
那么,如何将ProgressBar绑定到另一个线程中更新的值

提前谢谢

编辑:我已经切换到使用Gravell先生编写并链接到的ThreadedBinding实现。不过,我仍然会遇到交叉线程异常。在异常对话框中按“Break”将突出显示
PropertyChanged(这是新的PropertyChangedEventArgs(字段))行作为导致异常的行

我还需要换什么

编辑:看起来Gravell先生的职位已被删除。我提到的ThreadedBinding实现可以在本线程末尾找到:


在本例中,我已切换回普通的旧绑定,以便于其他人进行编译。

不幸的是,我认为交叉线程问题会使数据绑定在这里使用起来有点太笨拙,并且可能比任何情况下都要复杂——数据只需要以一种方式进行探测

您可以使用如下事件处理程序替换绑定:

private void ProgressPropertyChangedHandler(object sender,
                                            PropertyChangedEventArgs args)
{
    // fetch property on event handler thread, stash copy in lambda closure
    var progress = LongOp.Progress;

    // now update the UI
    pbProgress.Invoke(new Action(() => pbProgress.Value = progress));
}