2

我正在尝试创建一个线程,它将不断检查值的更改,然后在位于我的 GUI 中的 PictureBox 中直观地显示该更改。

我实际写的有点复杂,所以我在保持基本思想的同时简化了它,如果这还不够,我很乐意提供澄清:

public class CheckPictures
{
    PictureBox update;
    List<String> check;

    public CheckPictures(PictureBox anUpdate, List<String> aCheck)
    {
        update = anUpdate;
        check = aCheck;
    }

    public void start()
    {
        while(true)
        {
            if (aCheck[0] == "Me")
            {
                update.Image = Image.fromFile("");
            }
        }
    }
}

static int Main(string[] args)
{ 
    List<String> picturesList = new List<String>();

    CheckPictures thread1 = new CheckPictures(PictureBox1, picturesList);
    Thread oThread1 = new Thread(thread1.start));
}

如果我要将字符串“Me”添加到图片列表中,我想要它做的是动态更改 PictureBox1 中的图片。上面的代码没有像我希望的那样工作。我原以为通过传递实际的 PictureBox 和 List,对其他地方的 List 的任何更改都是程序将被线程捕获。所以我的第一个问题是:这可能吗?如果是这样,我需要对我的代码进行哪些更改才能实现它?

4

3 回答 3

2

您可能想要使用事件。您注册一个事件处理程序,当一个线程中发生某些变化时,它会调用另一个线程中的事件处理程序来完成工作。忙等待浪费cpu。

于 2012-04-16T20:54:47.100 回答
1

绝对不想做一个无限循环,这只会消耗cpu:

while(true)
{
      if (aCheck[0] == "Me")
      {
            update.Image = Image.fromFile("");
      }
 }

我认为您应该研究CountdownLatch类。

public class CountdownLatch
  {
    private int m_remain;
    private EventWaitHandle m_event;

    public CountdownLatch(int count)
    {
      m_remain = count;
      m_event = new ManualResetEvent(false);
    }

    public void Signal()
    {
      // The last thread to signal also sets the event.
      if (Interlocked.Decrement(ref m_remain) == 0)
        m_event.Set();
    }

    public void Wait()
    {
      m_event.WaitOne();
    }
  }

这里的基本思想是,您需要在线程上停止执行一段时间,并在满足某个条件时恢复(可能在另一个线程上)。

换句话说,您将拥有一个计数器,在特定条件下递减它的值,每当它变为零时,您就会触发您的事件,执行一些代码然后重新开始(停止执行并等待计数器变为零)。

在您的情况下,您可以将计数器设置为 1 并在您设置时递减它的值aCheck[0] = "Me";。这样您就不会浪费 CPU。

伪代码:

初始化计数器:

CountdownLatch latch = new CountdownLatch(1);

让线程等待:

public void start()
{
    while(true)
    {
      latch.Wait(); //execution stops
      {
          //execution resumes once the latch counter is zero.
          if (aCheck[0] == "Me")  //double check you have what you need
          {
              update.Image = Image.fromFile("");
              latch = new CountdownLatch(1); //reset if you need to do it again
          }
      }
    }
}

每当满足您的条件时(即aCheck[0] = "Me";)向您的锁存器发出信号:

latch.Signal();

最后一行将使线程恢复执行。好东西。

于 2012-04-16T20:51:42.073 回答
1

添加新图片时创建一些对象,该对象将引发事件。例如代表图片集合的类:

public class PicturesCollection
{
    public event EventHandler<PictureAddedEventArgs> PictureAdded;
    private List<string> _pictures = new List<string>();

    public void Add(string name)
    {
        _pictures.Add(name);
        if (PictureAdded != null)
            PictureAdded(this, new PictureAddedEventArgs(name));
    }

    public IEnumerable<string> Pictures
    {
        get { return _pictures; }
    }
}

如果您想为事件提供一些额外的数据,请创建自定义 EventArgs:

public class PictureAddedEventArgs : EventArgs
{
    public PictureAddedEventArgs(string name)
    {
        Name = name;
    }

    public string Name { get; private set; }
}

您现在需要的一切 - 创建图片集并订阅该事件:

static int Main(string[] args)
{ 
    PicturesCollection pictures = new PicturesCollection();
    pictures.PictureAdded += Pictures_PictureAdded;
}

static void Pictures_PictureAdded(object sender, PictureAddedEventArgs e)
{
    if (e.Name == "Me")
        PictureBox1.Image = Image.fromFile("");
}

如果您在应用程序的某处将新图片添加到集合中,它将引发 PictureAdded 事件,您可以处理和更新 PictureBox。在这种情况下不会浪费 CPU。

于 2012-04-16T21:12:54.450 回答