лентата на прогреса не напредва с помощта на Backgroundworker

Използвам фонов работник, за да актуализирам някои таблици в sqlserver. максималната лента на прогреса се настройва на правилната стойност, стойността на лентата на прогреса се увеличава, backgroundworker progresschanged се извиква правилно с правилна стойност, но лентата не напредва.

ето кода за формата в метода background_dowork има цикъл, който извиква updateProgressBarValue, който работи с правилни стойности.

public InterfaceConvertLonLat()
{
    InitializeComponent();
    Shown += new EventHandler(Form1_Shown);
    backgroundWorker1.WorkerReportsProgress = true;
    backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
    backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
}

public void ConvertLonLat_Load(object sender, EventArgs e)
{ 
}

public void updateProgressBarValue()
{
    progressBar1.Value++;
    backgroundWorker1.ReportProgress(progressBar1.Value);
}

public void setProgressBarMax(int max)
{
    progressBar1.Maximum = max;
    MessageBox.Show("setprogressbarmax " + max);
}

public void Form1_Shown(object sender, EventArgs e)
{     
    backgroundWorker1.RunWorkerAsync();
}

public void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    convert.OSGB36ToWGS84("paf");
}

public void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progressBar1.Value = e.ProgressPercentage;
}

тук е цикълът, съдържащ се в друг клас, който извиква updateprogressbarvalue, това се задейства и както е посочено backgroundworker1_progressChanged се задейства, но лентата не се движи.

con.setProgressBarMax(address.Tables[0].Rows.Count); 

foreach (DataRow LonLat in address.Tables[0].Rows)
{
    con.updateProgressBarValue();
    Double lon = 0;
    Double lat = 0;
    lat = Convert.ToDouble(LonLat["LTO"]);
    lon = Convert.ToDouble(LonLat["LGO"]);
    LocalToWGS84(ref lat, ref lon, OGB_M);

    cmd1.Parameters["@LTW"].Value = lat;
    cmd1.Parameters["@LGW"].Value = lon;

    string dbQuery1 = "update " + tableName + " set LTW = @LTW, LGW = @LGW";

    cmd1.CommandText = (dbQuery1);
    cmd1.CommandType = CommandType.Text;
    cmd1.Connection = conn;
    cmd1.ExecuteNonQuery();
}
}
catch (Exception e)
{
    MessageBox.Show("error converting: " + e.Message);
}
finally
{
    conn.Close();
}

person Jed I    schedule 02.10.2012    source източник
comment
Не трябва ли да се обаждате на ReportProgress или updateProgressBarValue от DoWork?   -  person Tudor    schedule 02.10.2012
comment
Не виждам никаква връзка между вашия метод DoWork и метода updateProgressBarValue.   -  person Tudor    schedule 02.10.2012
comment
Аз съм този метод convert.OSGB36ToWGS84(paf) е в различен клас вътре в този клас, който нарича updateprogressbarvalue   -  person Jed I    schedule 02.10.2012


Отговори (4)


Когато докладвате напредък, трябва да задействате събитие от фоновия работник, за да кажете на лентата на прогреса, че има нужда от актуализиране. Това може да стане с помощта на следното:

backgroundWorker1.ReportProgress(10);

Променете стойността на тази, от която се нуждаете, за да демонстрирате увеличен напредък във вашия код. Събитието за промяна на прогреса ще се изпълнява най-вече в същата нишка като вашия GUI, така че не би трябвало да имате проблеми с кръстосани нишки. Едно изключение е, ако вашият формуляр се извиква от Excel чрез addin, в който случай Excel ще бъде в главната нишка.

person InContext    schedule 02.10.2012
comment
updateProgressBarValue() се извиква от цикъл, който извиква backgroundWorker1.ReportProgress(progressBar1.Value); - person Jed I; 02.10.2012
comment

Използвал съм този трик преди за вертикално подравняване:

HTML:

<div id="container">
    <div class="center">vertically centered content</div>
</div>

CSS:

#container { white-space:nowrap; height:200px; }
#container:before { content:""; display:inline-block; width:0; height:100%; vertical-align:middle; }
.center { display:inline-block; vertical-align:middle; white-space:normal; }

Това създава псевдоелемент преди елемента с class="center" и използва inline-block, така че стилът vertical-align влиза в сила.

Ето jsfiddle, за да можете да проверите дали работи за вас: http://jsfiddle.net/Etzpj/

Мисля, че във вашия случай ще трябва да обвиете текста на всяка клетка с друг елемент, за да работи този трик.

Редактиране: тук използвах този трик във вашата цигулка http://jsfiddle.net/J8rL7/25/

- person InContext; 02.10.2012

Имате редица проблеми - вашият UpdateprogressBarValue() просто увеличава стойността на лентата за напредък, но не следи колко пъти е бил извикан / каква е текущата стойност - така че ако го извикате 101 пъти (приемайки диапазон от 0-100), ще получите OutOfRangeException

Вашият DoWork() метод изглежда изобщо не извиква актуализацията (нито директно, нито чрез повдигане на събитие).

Вие можете да използвате събития, за да направите това, но е по-добре да използвате делегати или може би анонимни функции. Нещо като...

public void setProgress(int value) {
    progressBar1.invoke(delegate{ progressBar1.Value = value; }
}

тогава просто извикайте setProgress(0) до setProgress(progressBar1.MaxValue) от вашия DoWork() метод

person Basic    schedule 02.10.2012
comment
updateprogressBarValue ще се увеличава само до максимума, който е зададен от броя на записите в таблицата, няма да надвишава това. Мислех, че намерението е фоновият работник да свърши по-голямата част от работата, оставяйки потребителския интерфейс да актуализира лентата за напредък - person Jed I; 02.10.2012
comment
Все още съм малко неясен по отношение на вашата архитектура тогава - от разширения кодов фрагмент, вашият фонов работник препраща директно към вашия InterfaceConvertLonLat чрез con променлива - така че работникът създава (формуляр?), който след това има препратка обратно към работника ? Изглежда, че имате референции, които вървят и в двете посоки? Във всеки случай, вашият работник (нишка A) извиква con.updateProgressBarValue(), което от своя страна увеличава progressBar1.value() контрола на UI нишката - което ще бъде коренът на вашия проблем. Можете ли да предоставите повече разяснения относно потока на изпълнение? - person Basic; 02.10.2012

Следното е сериозно погрешно:

public void updateProgressBarValue()
{
    progressBar1.Value++;   // not thread-safe
    backgroundWorker1.ReportProgress(progressBar1.Value);

}

ReportProgress() е предназначен да се нарича от DoWork, той дори не трябва да чете свойство Control.
Трябва да поддържате брояч в цикъла foreach и да подадете това към механизма за прогрес.

Сега това не показва директно защо не се движи, но нямате Завършен манипулатор. Сигурни ли сте, че процесът изобщо е приключил?

Ако изключение избяга от вашия DoWork, никога няма да разберете какво се е случило.

person Henk Holterman    schedule 02.10.2012

Мисля, че това може да е причинено от факта, че потребителският интерфейс в windows forms работи в собствена нишка/контекст. В този случай вероятно трябва да използвате Invoke, за да направите корекции в потребителския интерфейс.

Нещо като това:

public void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    Invoke(new ProgressDelegate(UpdateProgress), e.ProgressPercentage);
}

delegate void ProgressDelegate(decimal value);

private void UpdateProgress(decimal value)
{
    progressBar1.Value = value;
}
person Christoffer    schedule 02.10.2012
comment
Това не е правилно. Манипулаторът на събитие на ProgressChanged се изпълнява в нишката на потребителския интерфейс. - person Tudor; 02.10.2012