Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Общие вопросы по .NET и C# > Использование делегата для ProgressBar


Автор: MasterOfCode 15.10.2008, 08:18
Пытаюсь разобраться с делегатами, помогите понять как правильней.

У меня есть класс, который работает с БД. Есть процедура у класса, которая перекачивает данные из одной БД в другую. Есть цикл в процедуре в ходе которого должен изменяться ProgressBar.Position. Подскажите, необходимо ли в данном случаи использовать делегат. Если да, то как, т.е. в каком месте его объявить и как использовать? 
Или же лучше просто ссылку на контрол в процедуру передать и все? 

Автор: elbjarn 15.10.2008, 14:39
Цитата(MasterOfCode @  15.10.2008,  08:18 Найти цитируемый пост)
Или же лучше просто ссылку на контрол в процедуру передать и все?  

ни в коем случае. во-первых, кросстредовые обращения к контролам небезопасны. вы можете работать с контролом только в контексте того потока, в котором он был создан. для доступа к нему из других потоков, вы должны вызвать делегат из "родного" ему потока, чтобы ваш поток был приостановлен на какое-то время, а родной поток смог выполнить работу с контролом.
Код

public delegate void ProgressChanged(int progress);
    
    public class MyThread
    {
        public ProgressChanged pc = null;
        public void Start()
        {
            int n = 1000;
            for (int i = 0; i < n; i++)
            {
                int progress = i * 100 / n;
                if (pc != null)
                    pc(progress);
                for (int j = 0; j < n; j++)
                    for (int k = 0; k < n; k++)
                    {
                        int a = 0;
                        a++;
                    }
            }
        }
    }


//где-то в форме
public partial class myForm : Form
{
  // ....
  public void DoIt()
 {
            MyThread mt = new MyThread();
            mt.pc = SetProgress;

            System.Threading.Thread thread = new System.Threading.Thread(mt.Start);
            
            thread.Start();
 }
  
public void SetProgress(int progress)
        {
            if (textBox1.InvokeRequired)
            {
                ProgressChanged pc = new ProgressChanged(SetProgress);
                textBox1.Invoke(pc, progress);
            }
            else
            {
                textBox1.Text = string.Format("Выполнено: {0}%", progress);
            }
        }
}


Добавлено @ 14:45
вызовы InvokeRequired и Invoke для контрола как раз-таки нужны для обеспечения нитебезопасности, а вот метод Start() я поместил в отдельный класс вместе с ссылкой на делегат просто для удобства, полями этого класса могут стать и другие переменные, которые вы захотите сделать доступными методу треда. вместо всего этого, кстати, можно было бы использовать просто параметризованный ThreadStart, т.е. такой, что ему передается при старте функции объект какого-то вашего класса, в который вы можете напихать все что угодно. это стандартный подход, пришел сюда из с++ и WinAPI программирования ([offtopic]там вновь создаваемый поток может получить LPVOID на какую-то область памяти, которую потом может попытаться интерпретировать как объект какого-то класса[/offtopic]), и его тоже часто используют.

Автор: MasterOfCode 16.10.2008, 07:45
Код

public void SetProgress(int progress)


Когда его вызывать?

Автор: MasterOfCode 16.10.2008, 08:12
Добавил 
Код

pc += new Form1.ProgressChanged(_frm.SetProgress);


Заработало. Только пришлось ссылку на форму передавать в мой класс. :(

Автор: MasterOfCode 16.10.2008, 13:58
Прошу прощения. Затупил smile

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)