绑定,线程和winforms

时间:2009-04-10 19:45:59

标签: c# winforms multithreading

如何将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));
        }
    }
}

那么如何将ProgressBar绑定到另一个线程中更新的值?

提前致谢

编辑: 我已经切换到使用Gravell先生编写并链接到的ThreadedBinding实现。我仍然得到了跨线程异常。在异常对话框中按“Break”会将PropertyChanged(this, new PropertyChangedEventArgs(field));行突出显示为导致异常的行。

我还需要改变什么?

编辑:看起来Gravell先生的帖子已被删除。我提到的ThreadedBinding实现可以在这个帖子的末尾找到:http://groups.google.com/group/microsoft.public.dotnet.languages.csharp/browse_thread/thread/69d671cd57a2c7ab/2f078656d6f1ee1f?pli=1

我在示例中切换回普通的旧Binding,以便于其他人编译。

1 个答案:

答案 0 :(得分:2)

不幸的是,我认为交叉线程问题会使数据绑定在这里使用有点过于笨拙,并且可能比您在任何情况下都需要更复杂 - 数据只需要以某种方式进行检测。

你可以用这样的事件处理程序替换绑定:

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