I'm having trouble with a updating a form label text from a managed thread and have put together a minimalist test case that hopefully illustrates my problem.
I'm using Microsoft Visual Studio Professional 2022 (64-bit) - Version 17.9.3.
My form has a button and label. When the button is clicked a managed thread is created which counts up to 10 and then terminates. The counter value is displayed in the label via a delegate, following the numerous examples on Stack Overflow. All that works, so far so good.
I declared the functionality of the counter thread in a class in the main Windows Form app header file MyForm.h.
public:
// Start of declaration
ref class CounterThreadClass {
public:
int count = 0;
Thread^ theThread;
ThreadTest01::MyForm^ theForm;
void Start() {
theThread->Start();
}
void Worker() {
for (int loop = 0; loop < 10; loop++) {
count++;
theForm->lblCountValueUpdate(count.ToString());
Thread::Sleep(1000);
Debug::Debug::WriteLine("count = {0}", count);
}
Debug::Debug::WriteLine("Thread ended with count = {0}", count);
}
};
// End of declaration
I created an instance of the class and wrapped the Worker() function into a form that ThreadStart() will accept.
CounterThreadClass^ CounterThread = gcnew CounterThreadClass();
void ThreadWorker() { CounterThread->Worker(); }
I defined a delegate to update the Form value.
CounterThreadClass^ CounterThread = gcnew CounterThreadClass();
void ThreadWorker() { CounterThread->Worker(); }
// Defined a deligate to update the Form Control
delegate void stringDeligate(String^ str);
void lblCountValueWorker(String^ text) {
lblCountValue->Text = text;
}
void lblCountValueUpdate(String^ text) {
stringDeligate^ action = gcnew stringDeligate(this, &MyForm::lblCountValueWorker);
this->BeginInvoke(action, text);
}
On button click, a handle to the form and is passed to CounterThread so it can access lblCountValueUpdate().
private: System::Void btnStart_Click(System::Object^ sender, System::EventArgs^ e) {
CounterThread->theForm = this;
CounterThread->theThread = gcnew Thread(gcnew ThreadStart(this, &MyForm::ThreadWorker));
CounterThread->Start();
}
All of the above code is in the main application header file MyForm.h and compiles and executes correctly.
However, my real task is much bigger than the example above, so I moved the declaration of the CounterThreadClass into its own header file, counter.h, code below. I included counter.h in MyForm.h and use the counter namespace.
#pragma once
#include "MyForm.h"
using namespace System;
using namespace System::Diagnostics;
using namespace Threading;
using namespace ThreadTest01;
namespace counter {
ref class CounterThreadClass {
public:
int count = 0;
Thread^ theThread;
ThreadTest01::MyForm^ theForm;
void Start() {
theThread->Start();
}
void Worker() {
for (int loop = 0; loop < 10; loop++) {
count++;
theForm->lblCountValueUpdate(count.ToString());
Thread::Sleep(1000);
Debug::Debug::WriteLine("count = {0}", count);
}
Debug::Debug::WriteLine("Thread ended with count = {0}", count);
}
};
}
When I compile it, I get the error message 'ThreadTest01': a name space with this name does not exist. The message is applied to the line using namespace ThreadTest01;. The top section of MyForm.h is below, and the name space clearly does exist.
#pragma once
#include "counter.h"
namespace ThreadTest01 {
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
using namespace System::Diagnostics;
using namespace Threading;
using namespace counter;
/// <summary>
/// Summary for MyForm
/// </summary>
public ref class MyForm : public System::Windows::Forms::Form
{
public:
MyForm(void)
Try as I might, I cannot get visibility of the ThreadTest01 namespace in counter.h.
Can anybody suggest what I might be doing wrong? Thanks in advance.