【问题标题】:Binding, threads and winforms绑定、线程和winforms
【发布时间】:2009-04-10 19:45:58
【问题描述】:

如何将 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。

【问题讨论】:

    标签: c# winforms multithreading


    【解决方案1】:

    不幸的是,我认为跨线程问题会使数据绑定变得有点笨拙,无法在此处使用,而且在任何情况下都可能比您需要的更复杂——数据只需要以一种方式进行探测。

    您可以将绑定替换为这样的事件处理程序:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-12-14
      • 2010-10-10
      • 2011-02-15
      • 2011-12-27
      • 1970-01-01
      • 2018-07-04
      • 1970-01-01
      • 2014-08-11
      相关资源
      最近更新 更多