【问题标题】:Update UI from Class (multithreaded)? [duplicate]从类(多线程)更新 UI? [复制]
【发布时间】:2012-12-28 15:38:52
【问题描述】:

可能重复:
How to update the GUI from another thread in C#?

如何从线程类更新我的 UI?无法从线程访问更新表单控件。我想根据每个特定线程的进度更新我的 UI。

class MyClass
    {
        public delegate void CountChangedEventHandler(int vCount, int vIndex);
        public event CountChangedEventHandler CountChanged;

        private int count;
        private int index;

        public MyClass(int index)
        {
            this.index = index;
        }

        public int Count
        {
            get { return this.count; }
            set
            {
                this.count = value;
                if (this.CountChanged != null)
                    this.CountChanged(value, this.index);
            }
        }

        public void DoWork(object o)
        {
            for (int i = 0; i < 10000; i++)
            {
                this.Count = i;
            }
        }
    }

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 3; i++)
            {
                MyClass myCount = new MyClass(i);
                myCount.CountChanged += new MyClass.CountChangedEventHandler(UpdateUI);

                ListViewItem lvi = new ListViewItem();
                lvi.Text = "Thread #" + i.ToString();
                lvi.SubItems.Add("");
                listView1.Items.Add(lvi);

                ThreadPool.QueueUserWorkItem(new WaitCallback(myCount.DoWork));

            }
        }

        private void UpdateUI (int index, int count)
        {
            listView1.Items[index].SubItems[0].Text = count.ToString();
        }
    }

【问题讨论】:

标签: c# multithreading user-interface


【解决方案1】:

您需要使用InvokeBeginInvoke 将UI 访问封送回UI 线程。

我建议在这种情况下使用Invoke,因为这会阻止你的循环过于超前:

private void UpdateUI (int index, int count)
{
  Invoke( ( MethodInvoker ) (
    () => listView1.Items[index].SubItems[0].Text = count.ToString()
  ) );
}

【讨论】:

    【解决方案2】:

    有多种方法可以实现这一目标。这里有几个选项:

    1) BackgroundWorker - 你可以在网上找到很多关于如何使用它的例子,只要你只需要在过程中将进度(整数)传回 UI 就可以了。

    2) 带有计时器的消息队列 - 让您可以选择将进度传递回 UI。

    这是我编写的 WPF 应用程序中选项 2 的示例,它将字符串传递回 UI,当然,您可以将字符串替换为所需的任何自定义对象。此外,需要 .NET 3.0 或更高版本:

    private static List<string> MessageQueue = new List<string>();
    
    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        DispatcherTimer messageQueueTimer = new DispatcherTimer();
        messageQueueTimer.Tick += messageQueueTimer_Elapsed;
        messageQueueTimer.Interval = new TimeSpan(1); //1 tick
        messageQueueTimer.Start();
    }
    
    protected void messageQueueTimer_Elapsed(object sender, EventArgs e)
    {
        lock(MessageQueue)
        {
            //Read message from queue and remove it.
        }
    }
    
    //WriteLine can be called from any asyncronous method spawed from the UI.
    public void WriteLine(string message)
    {
        lock(MessageQueue)
        {
            //Insert message into the queue.        
        }
    }
    

    还有其他几种方法可以实现这一点,但这应该可以帮助您入门。希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-07
      • 1970-01-01
      • 2013-07-26
      • 1970-01-01
      相关资源
      最近更新 更多