I can't get background worker to work. This is my first time using it so I don't know if I have done something wrong. Here's my code:
int cardcount = 0;
string lev = "";
string att = "";
string atk = "";
string def = "";
string ctp = "";
string id = "";
void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if (folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
string folder = folderBrowserDialog1.SelectedPath;
DirectoryInfo dinfo = new DirectoryInfo(folderBrowserDialog1.SelectedPath);
FileInfo[] Files = dinfo.GetFiles("*.jpg");
int count = Files.Length;
int current = 0;
foreach (FileInfo file in Files)
{
string path = Path.GetFileNameWithoutExtension(file.Name);
int cardid = Convert.ToInt32(path);
if (Program.CardData.ContainsKey(cardid))
{
DevPro_CardManager.cardmaker.IMG = LoadBitmap(folderBrowserDialog1.SelectedPath + "//" + file.Name);
id = Program.CardData[cardid].Id.ToString();
lev = Program.CardData[cardid].Level.ToString();
att = Program.CardData[cardid].Attribute.ToString();
if (att == "1")
{
att = "earth";
}
else if (att == "2")
{
att = "water";
}
else if (att == "4")
{
att = "fire";
}
else if (att == "8")
{
att = "wind";
}
else if (att == "16")
{
att = "light";
}
else if (att == "32")
{
att = "dark";
}
else if (att == "64")
{
att = "divine";
}
if (Program.CardData[cardid].Atk.ToString() == "-2")
{
atk = "????";
}
else
{
atk = Program.CardData[cardid].Atk.ToString();
}
if (Program.CardData[cardid].Def.ToString() == "-2")
{
def = "????";
}
else
{
def = Program.CardData[cardid].Def.ToString();
}
ctp = Program.CardData[cardid].Type.ToString();
if (ctp == "2" || ctp == "130" || ctp == "65538" || ctp == "131074" || ctp == "262146" || ctp == "524290")
{
ctp = "spell";
}
else if (ctp == "4" || ctp == "1048580" || ctp == "131076")
{
ctp = "trap";
}
else if (ctp == "129" || ctp == "161")
{
ctp = "ritual";
}
else if (ctp == "65" || ctp == "97")
{
ctp = "fusion";
}
else if (ctp == "8193" || ctp == "8225" || ctp == "12321")
{
ctp = "synchro";
}
else if (ctp == "8388609" || ctp == "8388641")
{
ctp = "xyz";
}
else if (ctp == "33" || ctp == "545" || ctp == "1057" || ctp == "2081" || ctp == "4129" || ctp == "4194337")
{
ctp = "effect";
}
else if (ctp == "17" || ctp == "4113")
{
ctp = "normal";
}
else if (ctp == "16401")
{
ctp = "token";
}
cardcount = cardcount + 1;
backgroundWorker1.ReportProgress((current * 100) / count);
}
}
}
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// The progress percentage is a property of e
progressBar1.Value = e.ProgressPercentage;
label8.Text = cardcount.ToString();
comboBox2.SelectedItem = lev;
comboBox1.SelectedItem = att;
textBox2.Text = atk;
textBox1.Text = def;
comboBox3.SelectedItem = ctp;
GenerateCard();
ImageResizer.CropImage(361, 523, pictureBox1.Image, #"anime cards\" + Path.GetFileName(id));
}
And the code for the button that launches it:
private void button5_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
Please help or say if I'm doing something wrong, thanks.
If you really need to call ShowDialog from the background thread you will need to marshal the call to the foreground thread using Invoke. Here's an example of how you might do this:
public partial class Form1 : Form
{
private delegate DialogResult ShowFolderBrowser();
public Form1()
{
InitializeComponent();
}
private DialogResult ShowFolderBrowserDialog()
{
return this.folderBrowserDialog1.ShowDialog();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
if ((DialogResult)this.Invoke(this.ShowFolderBrowserDialog) == DialogResult.OK)
{
// ...
}
}
private void button1_Click(object sender, EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync();
}
}
However, I would recommend that you rethink your design somewhat. You never explained why you're using a BackgroundWorker in the first place. Why can't you start up the BackgroundWorker after you've shown the folder browser dialog? Like this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
string folder = e.Argument as string;
// ...
}
private void button1_Click(object sender, EventArgs e)
{
if (this.folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
string folder = this.folderBrowserDialog1.SelectedPath;
this.backgroundWorker1.RunWorkerAsync(folder);
}
}
}
The most important detail you overlooked is that you have to do something reasonable when the worker threw an exception. At a minimum, you'll have to report it in your RunWorkerCompleted event handler:
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
if (e.Error != null) {
MessageBox.Show(e.Error.ToString());
}
else {
// etc..
}
}
You will now also discover the problem in your code, you cannot use OpenFileDialog on a worker thread. Display it on the UI thread instead and then start the worker, passing the selection.
And yes, this is different from what you are used to, you expect the debugger to tell you about unhandled exceptions. That doesn't work the same way when a try/catch is wrapping code, they are built into the BackgroundWorker class. You can get the debugger to stop at such an invisible exception with Debug + Exceptions, tick the Thrown checkbox for CLR exceptions. This is not otherwise a good reason to skip the e.Error check in the event handler.
Related
I know it's already been written about.
Everything looks very good. But when I move to the right to see the rest of the columns, the rows in DataDridView start blinking very much. I can't solve this.
private void registersDataGridView_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
DataGridViewRow rowDataGridView = null;
string dataPropertyName;
dataPropertyName = this.registersDataGridView.Columns[e.ColumnIndex].DataPropertyName;
int isApprovedColumnIndex = this.registersDataGridView.Columns[isApprovedColumnName].Index;
int isCancelledColumnIndex = this.registersDataGridView.Columns[isCancelledColumnName].Index;
bool theColorHasBeenSet = false;
if (e.RowIndex >= 0 && e.RowIndex != btregisterDgvRowIndex)
{
rowDataGridView = this.registersDataGridView.Rows[e.RowIndex];
if (this.registersDataGridView.Columns[isCancelledColumnIndex].DataPropertyName == "IsCancelled")
{
if (rowDataGridView.Cells[isCancelledColumnIndex].Value != null && rowDataGridView.Cells[isCancelledColumnIndex].Value.ToString() == "Tak")
{
if (rowDataGridView.DefaultCellStyle.BackColor != Color.PaleVioletRed)
{
rowDataGridView.DefaultCellStyle.BackColor = Color.PaleVioletRed;
}
theColorHasBeenSet = true;
}
else
{
if (rowDataGridView.DefaultCellStyle.BackColor != Color.Ivory)
{
rowDataGridView.DefaultCellStyle.BackColor = Color.Ivory;
}
}
btregisterDgvRowIndex = e.RowIndex;
}
if (this.registersDataGridView.Columns[isApprovedColumnIndex].DataPropertyName == "IsApproved")
{
if (!theColorHasBeenSet)
{
if (rowDataGridView.Cells[isApprovedColumnName].Value != null && rowDataGridView.Cells[isApprovedColumnName].Value.ToString() == "-")
{
if (rowDataGridView.DefaultCellStyle.BackColor != Color.LightGray)
{
rowDataGridView.DefaultCellStyle.BackColor = Color.LightGray;
}
theColorHasBeenSet = true;
}
else if (rowDataGridView.Cells[isApprovedColumnName].Value != null && rowDataGridView.Cells[isApprovedColumnName].Value.ToString() == "Nie")
{
if (rowDataGridView.DefaultCellStyle.BackColor != Color.PaleVioletRed)
{
rowDataGridView.DefaultCellStyle.BackColor = Color.PaleVioletRed;
}
theColorHasBeenSet = true;
}
else
{
if (rowDataGridView.DefaultCellStyle.BackColor != Color.Ivory)
{
rowDataGridView.DefaultCellStyle.BackColor = Color.Ivory;
}
}
btregisterDgvRowIndex = e.RowIndex;
}
}
}
}
else
{
if (rowDataGridView.DefaultCellStyle.BackColor != Color.Ivory)
{
rowDataGridView.DefaultCellStyle.BackColor = Color.Ivory;
}
}
You're not setting the theColorHasBeenSet here which might cause it to change between Ivory and the next color on your list.
Your code seems to verbose to me, try the following
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.RowIndex < 0)
return;
var rowDataGridView = this.registersDataGridView.Rows[e.RowIndex];
Color GetBackgroundColor()
{
var isApprovedColumnIndex = this.registersDataGridView.Columns[isApprovedColumnName].Index;
var isCancelledColumnIndex = this.registersDataGridView.Columns[isCancelledColumnName].Index;
if (this.registersDataGridView.Columns[isCancelledColumnIndex].DataPropertyName == "IsCancelled")
{
var strValue = Convert.ToString(rowDataGridView.Cells[isCancelledColumnIndex].Value);
if (strValue == "Tak")
return Color.PaleVioletRed;
}
if (this.registersDataGridView.Columns[isApprovedColumnIndex].DataPropertyName == "IsApproved")
{
var strValue = Convert.ToString(rowDataGridView.Cells[isApprovedColumnIndex].Value);
if (strValue == "-")
return Color.LightGray;
if (strValue == "Nie")
return Color.PaleVioletRed;
}
return Color.Ivory;
}
rowDataGridView.DefaultCellStyle.BackColor = GetBackgroundColor();
}
I am creating a scheduler where data I entered below on two textboxes have to appear according to the Day or week and Time values. I've tried with the following code, but didn't work.
private void btnEnterData_click(object sender, System.EventArgs e)
{
if (((cmbDayWeek.SelectedIndex == 0) && (chb910.Checked == true)))
{
rtb1.Text = (tbxMedNumAppn.Text + tbxDocSpecAppn.Text);
}
else if (((cmbDayWeek.SelectedIndex == 0) && (chb1011.Checked == true)))
{
rtb7.Text = (tbxMedNumAppn.Text + tbxDocSpecAppn.Text);
}
return;
//and codes all the way down
}
private void btnSavePatient_Click(object sender, EventArgs e)
{
if (((cmbDayWeek.SelectedIndex == 0) && (chb910.Checked == true)))
{
rtb1.Show();
}
if (((cmbDayWeek.SelectedIndex == 0) && (chb1011.Checked == true)))
{
rtb2.Show();
}
// codes all the way down
}
P.S. I'm assuming that I have to use If/Else statement, but I can't get the logic fully :(
Image of the scheduler:
I'm using a BackgroundWorker to fetch data and update my UI. The code it's pretty self explanatory. When I click connect it connects to CANbus, starts background worker which fetches data and updates UI, when I click disconnect it stops fetching data from CANbus.
It works only for first time, when I'm trying to connect for the second time I'm getting an exception at RunWorkerAsync call which is inside RunWorkerCompleted callback about BackgroundWorker being busy and it cannot process more than one task at once.
That's what I don't quite understand, I'm making new instance of BackgroundWorker on every connection and have no idea why it's busy.
Looking for advice - thanks.
CANALHandle h;
BackgroundWorker canWorker;
private void bConnect_Click(object sender, RoutedEventArgs e)
{
if (this.h == 0) {
this.h = CANAL.CANALOpen("ED000200; 500", CANAL.FLAG_NONE);
canWorker = new BackgroundWorker();
canWorker.WorkerSupportsCancellation = true;
canWorker.WorkerReportsProgress = true;
canWorker.DoWork += (object s, DoWorkEventArgs ev) => {
if (CANAL.CANALDataAvailable(this.h) > 0) {
CANALMSG msg;
CANALStatus st = CANAL.CANALReceive(this.h, out msg);
ev.Result = msg;
}
};
canWorker.RunWorkerCompleted += (object s, RunWorkerCompletedEventArgs ev) => {
if (ev.Error != null) {
} else if (ev.Result != null) {
CANALMSG msg = (CANALMSG)ev.Result;
if (msg.id > 0) {
textCanId.Text = msg.id.ToString("X");
textCanLength.Text = msg.count.ToString("X");
textCanByte0.Text = (msg.count >= 1) ? msg.data[0].ToString("X2") : "";
textCanByte1.Text = (msg.count >= 2) ? msg.data[1].ToString("X2") : "";
textCanByte2.Text = (msg.count >= 3) ? msg.data[2].ToString("X2") : "";
textCanByte3.Text = (msg.count >= 4) ? msg.data[3].ToString("X2") : "";
textCanByte4.Text = (msg.count >= 5) ? msg.data[4].ToString("X2") : "";
textCanByte5.Text = (msg.count >= 6) ? msg.data[5].ToString("X2") : "";
textCanByte6.Text = (msg.count >= 7) ? msg.data[6].ToString("X2") : "";
textCanByte7.Text = (msg.count >= 8) ? msg.data[7].ToString("X2") : "";
}
}
canWorker.RunWorkerAsync();
};
canWorker.RunWorkerAsync();
}
}
private void bDisconnect_Click(object sender, RoutedEventArgs e)
{
if (this.h > 0) {
canWorker.CancelAsync();
canWorker.Dispose();
CANAL.CANALClose(this.h);
this.h = 0;
}
}
I have a backgroundworker dowork where inside I start a new backgroundworker
DirectoryInfo MySubDirectory;
List<FileInfo> l;
object[] CurrentStatus;
private void _FileProcessingWorker_DoWork(object sender, DoWorkEventArgs e)
{
int countmore = 0;
try
{
DirectoryInfo[] MySubDirectories = (DirectoryInfo[])e.Argument;
for (int i = 0; i < MySubDirectories.GetLength(0); i++)
{
MySubDirectory = MySubDirectories[i];
l = new List<FileInfo>();
if (_FileCountingWorker.IsBusy == false)
_FileCountingWorker.RunWorkerAsync();
CurrentStatus = new object[6];
int totalFiles = l.Count;
CurrentStatus[3] = i.ToString();
countmore += totalFiles;
CurrentStatus[4] = countmore;
_FileProcessingWorker.ReportProgress(0, CurrentStatus);
string CurrentDirectory = "Current Directory: " + MySubDirectory.Name;
foreach (FileInfo MyFile in l)
{
CurrentStatus = new object[6];
if (_FileProcessingWorker.CancellationPending)
{
e.Cancel = true;
return;
}
if (MyFile.Extension.ToLower() == ".cs" || MyFile.Extension.ToLower() == ".vb")
{
string CurrentFile = "Current File: " + MyFile.Name;
string CurrentFileWithPath = MyFile.FullName;
CurrentStatus[0] = CurrentDirectory;
CurrentStatus[1] = CurrentFile;
_FileProcessingWorker.ReportProgress(0, CurrentStatus);
List<string> Result = SearchInFile(CurrentFileWithPath, "if");
if (Result != null && Result.Count > 0)
{
CurrentStatus[2] = Result;
_FileProcessingWorker.ReportProgress(0, CurrentStatus);
}
}
}
}
}
catch (Exception err)
{
return;
}
}
I'm checking the other backgroundworker is not busy if not start it
if (_FileCountingWorker.IsBusy == false)
_FileCountingWorker.RunWorkerAsync();
In the new backgroundworker dowork event
private void _FileCountingWorker_DoWork(object sender, DoWorkEventArgs e)
{
CountFiles(MySubDirectory, l);
}
In CountFiles
int countingFiles = 0;
private void CountFiles(DirectoryInfo di, List<FileInfo> l)
{
try
{
l.AddRange(di.EnumerateFiles());
}
catch
{
string fff = "";
}
try
{
if (di.FullName != BasePath)
{
IEnumerable<DirectoryInfo> subDirs = di.EnumerateDirectories();
if (subDirs.Count() > 0)
{
foreach (DirectoryInfo dir in subDirs)
{
CountFiles(dir, l);
countingFiles += 1;
if (countingFiles == 8382)
{
string hhhhh = "";
}
CurrentStatus[5] = countingFiles;
_FileCountingWorker.ReportProgress(0,CurrentStatus);
}
}
}
}
catch
{
string yyy = "";
}
}
Then in the second backgroundworker progresschanged
private void _FileCountingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (typeof(object[]) == e.UserState.GetType())
{
object[] StatusMsg = (object[])e.UserState;
if (6 == StatusMsg.GetLength(0))
{
if (StatusMsg[5] != null)
{
lblCountingFiles.Text = StatusMsg[5].ToString();
}
}
}
}
The exception is on the line:
lblCountingFiles.Text = StatusMsg[5].ToString();
Cross-thread operation not valid: Control 'lblCountingFiles' accessed from a thread other than the thread it was created on
I'm updating the label in the ProgressChanged event. Why am I getting the exception?
And how should I solve it?
You are calling _FileCountingWorker.RunWorkerAsync(); in DoWork from another BackgroundWorker thread.
So when _FileCountingWorker reports progress it wont come back to the UI thread because it is not started from UI thread. That's why you are getting cross thread exception.
Try to call _FileCountingWorker.RunWorkerAsync() from UI thread or from _FileProcessingWorker_ProgressChanged event.
Otherwise you can use:
private void _FileCountingWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (!Dispatcher.CheckAccess()) // CheckAccess returns true if you're on the dispatcher thread
{
Dispatcher.Invoke(new Action<object, ProgressChangedEventArgs>(_FileCountingWorker_ProgressChanged), sender, e);
return;
}
if (typeof(object[]) == e.UserState.GetType())
{
object[] StatusMsg = (object[])e.UserState;
if (6 == StatusMsg.GetLength(0))
{
if (StatusMsg[5] != null)
{
lblCountingFiles.Text = StatusMsg[5].ToString();
}
}
}
}
I think the problem is on the main thread you have
object[] CurrentStatus;
in the background you could be newing it before reports progress gets to it
(or at the same time)
kill the above
just create the object in the do_work
object[] CurrentStatus = new object[6];
public void flow_Resize(object sender, PaintEventArgs e)
{
FlowLayoutPanel flow = sender as FlowLayoutPanel;
var item = listCtpMgr.FirstOrDefault(o => o.flp.Name == flow.Name);
if (item == null)
return;
addedCTP = (Microsoft.Office.Tools.CustomTaskPane)item.ctp;
if (addedCTP == null)
return;
ToolStrip _toolstrip = (ToolStrip)flow.Controls[0];
int MaxButtonWidthforThisToolbar = 0;
foreach (ToolStripItem toolStripItem in _toolstrip.Items)
{
if ((toolStripItem.Width) > MaxButtonWidthforThisToolbar)
{
MaxButtonWidthforThisToolbar = (toolStripItem.Width);
}
}
MaxButtonWidthforThisToolbar += 10;
if (addedCTP.DockPosition == MsoCTPDockPosition.msoCTPDockPositionLeft || addedCTP.DockPosition ==
MsoCTPDockPosition.msoCTPDockPositionRight)
{
if (addedCTP.Width < MaxButtonWidthforThisToolbar)
addedCTP.Width = MaxButtonWidthforThisToolbar;
}
else if (addedCTP.DockPosition == MsoCTPDockPosition.msoCTPDockPositionTop || addedCTP.DockPosition ==
MsoCTPDockPosition.msoCTPDockPositionBottom)
{
addedCTP.Height = 50;
}
else
{
addedCTP.Width = _toolstrip.Width + 27;
addedCTP.Height = _toolstrip.Height + 57;
}
}
Above Custom Task Pane Code is Working Fine in Word 2010 but in Word 2013 it is Flickring..Please Help ....I Used Resize also and SizeChange Also...