Cannot get access to Main form controls from a Managed thread. Windows Forms C++/CLI

21 Views Asked by At

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.

0

There are 0 best solutions below