К сожалению, во всех предыдущих ответах отсутствуют некоторые детали. Правильное решение немного громоздко, но это единственный способ сделать это правильно.
Вот как вы можете это сделать, точно сохраняя все детали и удобство использования:
A
и B
могут включать Ah и Bh в любом порядке Создайте два файла: A_def.h, B_def.h. Они будут содержать только определения A
и B
:
// A_def.h
#ifndef A_DEF_H
#define A_DEF_H
class B;
class A
{
int _val;
B *_b;
public:
A(int val);
void SetB(B *b);
void Print();
};
#endif
// B_def.h
#ifndef B_DEF_H
#define B_DEF_H
class A;
class B
{
double _val;
A* _a;
public:
B(double val);
void SetA(A *a);
void Print();
};
#endif
И тогда, Ah и Bh будут содержать это:
// A.h
#ifndef A_H
#define A_H
#include "A_def.h"
#include "B_def.h"
inline A::A(int val) :_val(val)
{
}
inline void A::SetB(B *b)
{
_b = b;
_b->Print();
}
inline void A::Print()
{
cout<<"Type:A val="<<_val<<endl;
}
#endif
// B.h
#ifndef B_H
#define B_H
#include "A_def.h"
#include "B_def.h"
inline B::B(double val) :_val(val)
{
}
inline void B::SetA(A *a)
{
_a = a;
_a->Print();
}
inline void B::Print()
{
cout<<"Type:B val="<<_val<<endl;
}
#endif
Обратите внимание, что A_def .h и B_def.h являются «частными» заголовками, пользователи A
и B
не должны их использовать. Общий заголовок - A.h и B.h.
Вам нужно выполнить длительную операцию в фоновом потоке.
Существует несколько способов сделать это.
ThreadPool.QueueUserWorkItem(new WaitCallback(YourMethod));
В .NET 4.0 вы можете использовать TaskFactory : Task.Factory.StartNew(() => YourMethod());
И в .NET 4.5 и более поздних версиях вы можете ( и вместо TaskFactory.StartNew()
следует использовать Task.Run()
: Task.Run(() => YourMethod());
Помните, что с чем-либо, связанным с потоком, вы не можете обновить GUI или изменить какой-либо графический интерфейс элементы управления из фоновой нити. Если вы хотите что-либо сделать в графическом интерфейсе, вы должны использовать Invoke (и InvokeRequired), чтобы вызвать метод обратно в потоке графического интерфейса. См. здесь .
Ничего не требуется. Используйте Application.DoEvents(); //repaint or respond to msg
Например:
foreach (DirectoryInfo subDir in dirInfo.EnumerateDirectories())
{
count = count + 1;
listBoxControl4.Items.Add(count.ToString() + ":" + subDir.FullName);
Application.DoEvents(); //allow repaint to see status
ProduceListing(subDir, " ");
}
Это будет проходить через все папки рекурсивно и записать имена в список. Это может занять много времени. С помощью DoEvents () он будет показывать прогресс в каждом цикле. В принципе, вызов позволяет окнам в этом потоке обновлять что-либо в цикле windows msg. Обязательно наблюдайте за непреднамеренной рекурсией, как любой элемент управления в форме, который нужно нажать, даже если ваш первый не завершился. Это хорошо работает. (Это копия старого вызова Delphi Application.ProcessMessages (). Вы можете найти это, чтобы понять, почему он работает и что нужно отслеживать.
Очевидно, вам нужно использовать фоновые потоки. Я предлагаю вам прочитать эту бесплатную электронную книгу .
private voidForm_Load(object sender, EventArgs e)
{
MethodInvoker mk = delegate
{
//your job
};
mk.BeginInvoke(callbackfunction, null);
}
private void callbackfunction(IAsyncResult res)
{
// it will be called when your job finishes.
}
use MethodInvoker - самый простой способ.