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


Автор: MasterOfCode 23.6.2009, 16:53
ComboBox который создается динамически, у него есть процедура
Код

        private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox cb = (ComboBox)sender;
            IFeatureLayer featureLayer;
            string layerName = cb.Name.Substring(2);
            featureLayer = (IFeatureLayer)axMapControl1.ActiveView.FocusMap.get_Layer(0);
            for (int i = 0; i < axMapControl1.ActiveView.FocusMap.LayerCount; i++)
            {
                featureLayer = (IFeatureLayer)axMapControl1.ActiveView.FocusMap.get_Layer(i);
                if (featureLayer.FeatureClass.AliasName.ToUpper() == layerName.ToUpper())
                    break;
            }
            ITable table = (ITable)featureLayer;
            IRow row;
            Panel pnl = (Panel)cb.Parent;
            ListBox lb = (ListBox)pnl.Controls.Find("lb"+featureLayer.FeatureClass.AliasName, false)[0];
            list = new List<string>();
            for (int i = 0; i < table.RowCount(null); i++)
            {
                row = table.GetRow(i);
                list.Add(row.get_Value(cb.SelectedIndex).ToString());
            }
            
            lb.DataSource = list;
        }
 
Бывает такое что в таблице тысячи записей, и при выполнении данной операции форма подвисает.
Я бы хотел вынести в отдельный поток,  там заполнять List<string> и автоматически на прогрессбар выводить, но не приложу ума как это сделать?

Автор: Bogdan1024 23.6.2009, 17:42
Ну, в ComboBox_SelectedIndexChanged запустить поток, а когда он закончится сделать lb.DataSource = list. Юзать метод Invoke у контролов чтобы получить доступ к их методам из других потоков.

Автор: MasterOfCode 23.6.2009, 18:06
Цитата(Bogdan1024 @  23.6.2009,  19:42 Найти цитируемый пост)
запустить поток, а когда он закончится сделать lb.DataSource = list.

Как проверить что поток завершил работу? 

Автор: DVariuS 23.6.2009, 18:10
MasterOfCode, юзай http://msdn.microsoft.com/ru-ru/library/system.componentmodel.backgroundworker.aspx  smile 

Автор: MasterOfCode 23.6.2009, 18:28
Цитата(DVariuS @  23.6.2009,  20:10 Найти цитируемый пост)
MasterOfCode, юзай BackgroundWorker  smile  

Юзал, не понравился он мне =)

Автор: Partizan 23.6.2009, 19:55
MasterOfCode, сразу говори чем =)

Автор: MasterOfCode 24.6.2009, 09:20
Цитата(Partizan @  23.6.2009,  21:55 Найти цитируемый пост)
сразу говори чем =) 

мне показалось неудобно работать с ним. компоненту на форму бросать. Попробовал через Thread, сравнил, выбрал второе =)

Помогите разобраться, может кто сталкивался:

Код

public partial class frmMap : Form
    {
        ProgressBar progressBar; // текущий прогресс бар
        ListBox listBox; // текущий листбокс
        public delegate void ProgressChanged(int progress);
        public delegate void ListBoxChanged(List<string> list);
        public ProgressChanged pc = null;
        public ListBoxChanged lc = null;

        public void SetProgress(int progress)
        {
            if (progressBar.InvokeRequired)
            {
                ProgressChanged pc = new ProgressChanged(SetProgress);
                progressBar.Invoke(pc, progress);
            }
            else
            {
                progressBar.Value = progress;
            }
        }

        public void SetListBoxDataSource(List<string> list)
        {
            if (listBox.InvokeRequired)
            {
                ListBoxChanged lc = new ListBoxChanged(SetListBoxDataSource);
                listBox.Invoke(lc, list);
            }
            else
            {
                listBox.DataSource = list;
            }
        }
        private void go(object parameters)
        {
            pc = SetProgress;
            lc = SetListBoxDataSource;
            object[] paramList = (object[])parameters;
            List<string> list = (List<string>)paramList[0];
            int selIdx = (int)paramList[2];
            ITable table = (ITable)paramList[1];
            IRow row;
            for (int i = 0; i < table.RowCount(null); i++)
            {
                row = table.GetRow(i);
                list.Add(row.get_Value(selIdx).ToString());
                if (pc != null)
                    SetProgress(i);
            }
            if (lc != null)
                SetListBoxDataSource(list);
            if (pc != null)
                SetProgress(0);
        }

        private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            ComboBox cb = (ComboBox)sender;
            IFeatureLayer featureLayer;
            string layerName = cb.Name.Substring(2);
            featureLayer = (IFeatureLayer)axMapControl1.ActiveView.FocusMap.get_Layer(0);
            for (int i = 0; i < axMapControl1.ActiveView.FocusMap.LayerCount; i++)
            {
                featureLayer = (IFeatureLayer)axMapControl1.ActiveView.FocusMap.get_Layer(i);
                if (featureLayer.FeatureClass.AliasName.ToUpper() == layerName.ToUpper())
                    break;
            }
            ITable table = (ITable)featureLayer;
            
            Panel pnl = (Panel)cb.Parent;
            ListBox lb = (ListBox)pnl.Controls.Find("lb"+featureLayer.FeatureClass.AliasName, false)[0];
            list = new List<string>();
            int selIdx = cb.SelectedIndex;
            listBox = lb; // устанавливаем текущий листбокс
            ProgressBar pb = (ProgressBar)pnl.Controls.Find("pb" + featureLayer.FeatureClass.AliasName, false)[0]; //устанавливаем выбраный прогрес бар
            object o = new object[] { list, table, selIdx };
            progressBar = (ProgressBar)pnl.Controls.Find("pb" + featureLayer.FeatureClass.AliasName, false)[0];
            progressBar.Maximum = table.RowCount(null);
            System.Threading.Thread thread = new System.Threading.Thread(go);
            thread.Start(o);
        }
    }

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

Автор: Conkistador 24.6.2009, 09:21
Цитата(MasterOfCode @ 23.6.2009,  18:28)
Цитата(DVariuS @  23.6.2009,  20:10 Найти цитируемый пост)
MasterOfCode, юзай BackgroundWorker  smile  

Юзал, не понравился он мне =)

и чем же не понравился ? 

Автор: Partizan 24.6.2009, 10:54
MasterOfCode, да BW на самом деле гораздо удобнее...

кидание компонента из тулбокса на форму - совсем не обязательное условие...можно точно также создать объект BackgroundWorker из кода...
всё что нужно - подписаться на событие DoWork и в обработчик поместить тот код, который должен выполняться в фоновом потоке. 

Ещё нужно подписаться на ProgressChanged, в обработчике которого и апдейтить контролы(когда в обработчике DoWork вызываешь ReportProgress, возникает ProgressChanged).

Ну и последним шагом надо просто запустить выполнение фоновой задачи вызовом метода RunWorkerAsync();

Автор: MasterOfCode 24.6.2009, 11:27
Partizan, как все просто =) Ладно, использую и ту и эту технологии, работы еще много.

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