C# 绑定、线程和winforms
如何将ProgressBar绑定到在另一个线程中更新的类的属性 下面的代码示例显示了我的第一次天真尝试。它不起作用,因为我得到了关于跨线程通信的运行时错误。我认为我需要以某种方式使用Invoke,但我不确定如何使用Binding类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
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));
}