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」をpictureListに追加する場合、PictureBox1の画像を動的に変更することです。上記のコードは、私が望んでいたようには機能しません。実際の PictureBox と List を渡すことで、別の場所で List を変更すると、プログラムはスレッドによってキャッチされると考えていました。だから私の最初の質問は:これは可能ですか?もしそうなら、それを達成するためにコードにどのような変更を加える必要がありますか?

4

3 に答える 3

2

イベントを使用したい場合があります。イベントハンドラーを登録すると、あるスレッドで何かが変更されると、別のスレッドでイベントハンドラーが呼び出されて処理されます。ビジー待機は CPU を浪費します。

于 2012-04-16T20:54:47.100 に答える
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 に答える
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 に答える