Управление поперечной резьбой - PullRequest
3 голосов
/ 06 февраля 2012

В настоящее время я пытаюсь создать таймер, который будет запускать фрагмент кода каждые несколько миллисекунд. проблема в том, что я хочу иметь возможность изменить положение графического блока, созданного в том же потоке, что и таймер, в результате я получаю сообщение об ошибке объекта Invoke, даже если оно не создано в исходном потоке?

private void frmMain_Load(object sender, EventArgs e)
{
    //Update Timer Thread
    UpdateThread = new Thread(new ThreadStart(UpdateWindow));
    SleepTime = (int)1000/MaxFps;
    UpdateThread.Start();        
    //.....
}

delegate void SetTextCB(string text);
delegate void SetControl(Control cntrl);

public void TimerThread()
{
    //Controls
    PictureBox TestPicBox;

    //Test TestPicBox
    TestPicBox = new PictureBox();
    TestPicBox.Image = Image.FromFile(TestImage.bmp");
    TestPicBox.Top = 20;
    TestPicBox.Left = 20;
    TestPicBox.Width = 64;
    TestPicBox.Height = 64;
    FilePanelControl(TestPicBox);

    while (true)
    {
        //--Sleep
        Thread.Sleep(SleepTime);
        //--FPS
        if (DateTime.Now.ToString("HH:mm:ss") != SystemTime)
        {
            if (blnShowFps) { lblFpsTextsSet(UpdateFps.ToString() + "-FPS"); }
            else { lblFpsTextsSet(""); }
            SystemTime = DateTime.Now.ToString("HH:mm:ss");
            UpdateFps = 0;
        }
        UpdateFps++;
        //Sleep Time
        SleepTime = (int)1000 / MaxFps;

        //Do UpDate Logic
        TestPicBox.location = new point(10,10);
    }
}

//--Add Control
private void FilePanelControl(Control added)
{
    if (this.FilePanel.InvokeRequired)
    {
        SetControl d = new SetControl(FilePanelControl);
        this.Invoke(d, new object[] { added });
    }
    else
    {
        this.FilePanel.Controls.Add(added);
    }
}

//--lblFps.text
private void lblFpsTextsSet(string text)
{
    if (this.lblFPS.InvokeRequired)
    {
        SetTextCB d = new SetTextCB(lblFpsTextsSet);
        this.Invoke(d, new object[] { text });
    }
    else
    {
        this.lblFPS.Text = text;
    }
}

в надежде, что мне не придется вызывать каждый элемент управления, который я объявляю в этой теме, поскольку планировалось создать список графических блоков, чтобы пользователь мог добавлять графические блоки по мере необходимости.

Спасибо за помощь.

Ответы [ 2 ]

3 голосов
/ 06 февраля 2012

Вы должны использовать System.Windows.Forms.Timer вместо создания собственного потока.

Таким образом, все уже будет в потоке пользовательского интерфейса.

1 голос
/ 06 февраля 2012

Те же InvokeRequired и Invoke (или BeginInvoke) должны использоваться для установки PictureBox.Location. Свойства элемента управления должны быть установлены в потоке, в котором был создан дескриптор элемента управления, что определяется WinForms, а не в том месте, где был создан сам элемент управления.

Причины объяснены в Control.InvokeRequired .

Вот дополнительная информация о многопоточности в элементах управления Windows Forms , которая включает пример использования фонового потока.

...