|
No idea ... but I don't use the designer except for UI controls - BW isn't that, and I create them in code as needed. It's trivial to do.
Here's my code for the UI component of my file mover:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.IO;
using System.Data.SqlClient;
using BackgroundFileMove.UtilityCode;
using System.Windows.Forms;
using Microsoft.WindowsAPICodePack.Taskbar;
using System.Reflection;
namespace BackgroundFileMove
{
public partial class frmMoveFilesInBackground : Form
{
#region Constants
private const int blockSize = 8 * 1024 * 1024;
#endregion
#region Fields
#region Internal
private volatile bool cancel = false;
private FileMove.MoveFile moveDelegate;
private FileMove.UpdateDB updateDelegate;
private IEnumerable<FileMove> files;
private string moveFileAction;
private string updateDBAction;
private string skippingAction;
private bool closeOnDone;
private byte[] transfer = new byte[blockSize];
private bool doCopyOnly = false;
#endregion
#region Property bases
#endregion
#endregion
#region Properties
public bool IsProcessing { get { return butStop.Enabled; } }
#endregion
#region Regular Expressions
#endregion
#region Enums
#endregion
#region Classes
private class ProgressReport
{
public string Filename { get; set; }
public string Action { get; set; }
public int FileNumber { get; set; }
public int FilesCount { get; set; }
public int FilePercentage { get; set; }
}
#endregion
#region Constructors
public frmMoveFilesInBackground(IEnumerable<FileMove> files,
FileMove.MoveFile moveDelegate = null,
FileMove.UpdateDB updateDelegate = null,
string moveFileAction = null,
string updateDBAction = null,
string skippingAction = null,
bool closeOnDone = false)
{
InitializeComponent();
if (moveFileAction == null) moveFileAction = "Moving title...";
if (updateDBAction == null) updateDBAction = "Updating database...";
if (skippingAction == null) skippingAction = "Skipping title...";
this.moveDelegate = moveDelegate;
this.updateDelegate = updateDelegate;
this.files = files;
this.moveFileAction = moveFileAction;
this.updateDBAction = updateDBAction;
this.skippingAction = skippingAction;
this.closeOnDone = closeOnDone;
string initData = "";
tbInfo.Text = initData;
tbInfo.Visible = cancel;
}
#endregion
#region Events
#region Event Constructors
public event EventHandler MoveCompleted;
protected virtual void OnMoveCompleted(EventArgs e)
{
EventHandler eh = MoveCompleted;
if (eh != null)
{
eh(this, e);
}
}
#endregion
#region Event Handlers
#region Form
private void frmMoveFilesInBackground_Shown(object sender, EventArgs e)
{
DoBackgroundMove();
}
private void frmMoveFilesInBackground_Load(object sender, EventArgs e)
{
if ((ModifierKeys & Keys.Shift) == 0)
{
this.LoadLocation();
}
}
private void frmMoveFilesInBackground_FormClosing(object sender, FormClosingEventArgs e)
{
if ((ModifierKeys & Keys.Shift) == 0)
{
this.SaveLocation();
}
}
#endregion
#region Buttons
private void butStop_Click(object sender, EventArgs e)
{
cancel = true;
}
#endregion
#region Worker
private void tidyFiles_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;
if (worker != null)
{
int fileNumber = 1;
worker.ReportProgress(0, new ProgressReport { Action = "Initializing", Filename = "", FileNumber = 0, FilesCount = 0 });
foreach (FileMove file in files)
{
ProgressReport pr = new ProgressReport { FilesCount = files.Count() };
if (cancel)
{
pr.Action = "Cancelled by user";
pr.Filename = "";
worker.ReportProgress(pr.FilesCount, pr);
break;
}
string title = file.Title;
string fnOld = file.OldPath;
string fnNew = file.NewPath;
Guid id = file.FileID;
pr.FileNumber = fileNumber;
pr.Filename = Path.GetFileNameWithoutExtension(fnOld);
if (fnNew != fnOld)
{
try
{
pr.Action = moveFileAction;
worker.ReportProgress(fileNumber, pr);
if (moveDelegate != null)
{
if (!moveDelegate(file))
{
continue;
}
}
else
{
if (File.Exists(fnOld))
{
string path = Path.GetDirectoryName(fnNew);
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
MoveFile(fnOld, fnNew, worker, pr);
}
else if (!File.Exists(fnNew))
{
throw new IOException("Neither the source nor the destination files could be found");
}
}
if (updateDelegate != null)
{
pr.Action = updateDBAction;
worker.ReportProgress(fileNumber, pr);
if (!updateDelegate(file))
{
break;
}
}
}
catch (Exception ex)
{
string problem = string.Format("Problem with:\n \"{0}\"\n \"{1}\"\n \"{2}\"\n {3}\n", title, fnOld, fnNew, ex);
worker.ReportProgress(fileNumber, new ProgressReport
{
Action = problem,
Filename = fnOld,
FileNumber = fileNumber,
FilesCount = files.Count()
});
}
}
else
{
pr.Action = skippingAction;
worker.ReportProgress(fileNumber, pr);
}
fileNumber++;
}
}
}
private void tidyFiles_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int progress = e.ProgressPercentage;
ProgressReport report = e.UserState as ProgressReport;
if (report == null)
{
tbInfo.Text = "Working...";
pbShow.Visible = false;
}
else
{
tbInfo.Lines = string.Format("{0}\n{1}/{2}\n{3}", report.Action, report.FileNumber, report.FilesCount, report.Filename).Split('\n');
pbShow.Maximum = report.FilesCount;
pbShow.Visible = true;
if (progress >= 0)
{
int newIndex = dgvHistory.Rows.Add(report.Action, report.Filename);
dgvHistory.CurrentCell = dgvHistory.Rows[newIndex].Cells[0];
Text = string.Format("Moving: {0}", report.Action);
TaskbarManager.Instance.SetProgressValue(report.FileNumber, report.FilesCount);
}
else
{
progress = -progress;
}
}
tbInfo.Visible = true;
if (report.FilePercentage > 0)
{
pbFileProgress.Visible = true;
pbFileProgress.Value = report.FilePercentage;
}
else
{
pbFileProgress.Visible = false;
}
pbShow.Value = progress;
}
private void tidyFiles_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pbShow.Visible = false;
pbFileProgress.Visible = false;
butStop.Enabled = false;
tbInfo.Text = "Completed";
Text = "Move operation completed";
TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.NoProgress);
OnMoveCompleted(new EventArgs());
if (closeOnDone)
{
Close();
}
}
#endregion
#endregion
#endregion
#region Public Methods
public void Cancel()
{
if (IsProcessing)
{
cancel = true;
}
}
public void SteathMove()
{
DoBackgroundMove();
}
#endregion
#region Public Static Methods
#region Do Copy
public static frmMoveFilesInBackground DoCopy(string sourceFolder,
string destinationFolder,
IEnumerable<string> wantedExtensions = null,
IEnumerable<string> unwantedExtensions = null,
FileMove.MoveFile moveDelegate = null,
FileMove.UpdateDB updateDelegate = null,
string moveFileAction = null,
string updateDBAction = null,
string skippingAction = null,
bool closeOnDone = false)
{
if (unwantedExtensions == null) unwantedExtensions = new List<string>();
List<FileMove> files = new List<FileMove>();
Cursor.Current = Cursors.WaitCursor;
string[] rawData = Directory.GetFiles(sourceFolder, "*.*", SearchOption.AllDirectories);
files.AddRange(rawData.Where(r => (wantedExtensions == null ? true : wantedExtensions.Contains(Path.GetExtension(r))) &&
!unwantedExtensions.Contains(Path.GetExtension(r)))
.Select(w => new FileMove(Path.GetFileNameWithoutExtension(w), w, w.Replace(sourceFolder, destinationFolder))));
Cursor.Current = Cursors.Default;
return DoCopy(files, moveDelegate, updateDelegate, moveFileAction, updateDBAction, skippingAction, closeOnDone);
}
public static frmMoveFilesInBackground DoCopy(IEnumerable<FileMove> files,
FileMove.MoveFile moveDelegate = null,
FileMove.UpdateDB updateDelegate = null,
string moveFileAction = null,
string updateDBAction = null,
string skippingAction = null,
bool closeOnDone = false)
{
frmMoveFilesInBackground move = new frmMoveFilesInBackground(files, moveDelegate, updateDelegate, moveFileAction, updateDBAction, skippingAction, closeOnDone);
move.doCopyOnly = true;
move.Show();
Cursor.Current = Cursors.Default;
return move;
}
#endregion
#region Do Move
public static frmMoveFilesInBackground DoMove(string sourceFolder,
string destinationFolder,
IEnumerable<string> wantedExtensions = null,
IEnumerable<string> unwantedExtensions = null,
FileMove.MoveFile moveDelegate = null,
FileMove.UpdateDB updateDelegate = null,
string moveFileAction = null,
string updateDBAction = null,
string skippingAction = null,
bool closeOnDone = false)
{
if (unwantedExtensions == null) unwantedExtensions = new List<string>();
List<FileMove> files = new List<FileMove>();
Cursor.Current = Cursors.WaitCursor;
string[] rawData = Directory.GetFiles(sourceFolder, "*.*", SearchOption.AllDirectories);
files.AddRange(rawData.Where(r => (wantedExtensions == null ? true : wantedExtensions.Contains(Path.GetExtension(r))) &&
!unwantedExtensions.Contains(Path.GetExtension(r)))
.Select(w => new FileMove(Path.GetFileNameWithoutExtension(w), w, w.Replace(sourceFolder, destinationFolder))));
Cursor.Current = Cursors.Default;
return DoMove(files, moveDelegate, updateDelegate, moveFileAction, updateDBAction, skippingAction, closeOnDone);
}
public static frmMoveFilesInBackground DoMove(IEnumerable<FileMove> files,
FileMove.MoveFile moveDelegate = null,
FileMove.UpdateDB updateDelegate = null,
string moveFileAction = null,
string updateDBAction = null,
string skippingAction = null,
bool closeOnDone = false)
{
frmMoveFilesInBackground move = new frmMoveFilesInBackground(files, moveDelegate, updateDelegate, moveFileAction, updateDBAction, skippingAction, closeOnDone);
move.Show();
Cursor.Current = Cursors.Default;
return move;
}
#endregion
public static string GetRevisionHistory()
{
Assembly assembly = Assembly.GetExecutingAssembly();
Stream stream = assembly.GetManifestResourceStream("BackgroundFileMove.Resources.Documents.RevisionHistory.txt");
StreamReader reader = new StreamReader(stream);
return reader.ReadToEnd();
}
public static bool IsDriveAvailable(string path)
{
DriveInfo[] drives = DriveInfo.GetDrives();
DriveInfo drive = drives.FirstOrDefault(d => path.StartsWith(d.Name));
return drive != null && drive.IsReady;
}
#endregion
#region Overrides
#endregion
#region Private Methods
private void DoBackgroundMove()
{
if (!cancel)
{
TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Normal);
BackgroundWorker tidyFiles = new BackgroundWorker();
tidyFiles.WorkerReportsProgress = true;
tidyFiles.DoWork += new DoWorkEventHandler(tidyFiles_DoWork);
tidyFiles.ProgressChanged += new ProgressChangedEventHandler(tidyFiles_ProgressChanged);
tidyFiles.RunWorkerCompleted += new RunWorkerCompletedEventHandler(tidyFiles_RunWorkerCompleted);
tidyFiles.RunWorkerAsync();
butStop.Enabled = true;
}
}
private void MoveFile(string src, string dst, BackgroundWorker worker = null, ProgressReport prMain = null)
{
if (src != dst)
{
int iSrc = src.IndexOf(':');
int iDst = dst.IndexOf(':');
FileInfo fiSrc = new FileInfo(src);
if (fiSrc.Length < blockSize || (iSrc > 0 && iDst > 0 && iSrc == iDst && src.Substring(0, iSrc) == dst.Substring(0, iDst)))
{
if (doCopyOnly)
{
File.Copy(src, dst);
}
else
{
File.Move(src, dst);
}
}
else
{
using (Stream sr = new FileStream(src, FileMode.Open))
{
using (Stream sw = new FileStream(dst, FileMode.Create))
{
long total = sr.Length;
long bytes = 0;
long cnt = total;
int progress = 0;
while (cnt > 0)
{
int n = sr.Read(transfer, 0, blockSize);
sw.Write(transfer, 0, n);
bytes += n;
cnt -= n;
int percent = (int)((bytes * 100) / total);
if (progress != percent)
{
progress = percent;
if (worker != null && prMain != null)
{
ProgressReport pr = new ProgressReport
{
FilesCount = prMain.FilesCount,
FileNumber = prMain.FileNumber,
Filename = prMain.Filename,
Action = prMain.Action,
FilePercentage = percent
};
worker.ReportProgress(-prMain.FileNumber, pr);
}
}
}
}
}
FileInfo fiDst = new FileInfo(dst);
fiDst.Attributes = fiSrc.Attributes;
fiDst.CreationTime = fiSrc.CreationTime;
fiDst.CreationTimeUtc = fiSrc.CreationTimeUtc;
fiDst.IsReadOnly = fiSrc.IsReadOnly;
fiDst.LastAccessTime = fiSrc.LastAccessTime;
fiDst.LastAccessTimeUtc = fiSrc.LastAccessTimeUtc;
fiDst.LastWriteTime = fiSrc.LastWriteTime;
fiDst.LastWriteTimeUtc = fiSrc.LastWriteTimeUtc;
if (!doCopyOnly)
{
File.Delete(src);
}
}
}
}
#endregion
}
} Look at the DoBackgroundMove method - it builds the worker as needed and kicks it off to throw files around (normally between my HDD and NAS, which is a relatively slow operation)
To use it, I construct the form instance, pass it the files list and show it - it then updates my as it moves the files.
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I finally could use Invoke to avoid cross-threading. But, UI still freezes and non-responsive during UI calculations.
My final code:
private void barButtonItem5_ItemClick(object sender, ItemClickEventArgs e)
{
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void CreateSheet(string _sheetName)
{
IWorkbook workbook = spreadsheetControl.Document;
if (workbook.Worksheets.Contains(_sheetName) == false)
{
workbook.Worksheets.Add().Name = _sheetName;
}
}
private void ClearSheet(string _sheetName)
{
IWorkbook workbook = spreadsheetControl.Document;
var keys = new List<string>();
var values = new List<int>();
Worksheet ws_summarized = workbook.Worksheets[_sheetName];
ws_summarized.Clear(workbook.Worksheets[_sheetName].GetUsedRange());
keys.Clear();
values.Clear();
}
private void FillCell(string _sheetName)
{
IWorkbook workbook = spreadsheetControl.Document;
Worksheet worksheet = workbook.Worksheets["DataSet1"];
CellRange range = worksheet.GetDataRange();
int LastRow = range.BottomRowIndex;
var keys = new List<string>();
var values = new List<int>();
for (int i = 0; i < LastRow + 1; i++)
{
if (worksheet.Cells[i, 10].DisplayText == "خاتمه یافته")
{
keys.Add(string.Join(",", worksheet.Cells[i, 28].DisplayText, worksheet.Cells[i, 0].DisplayText, worksheet.Cells[i, 9].DisplayText,
worksheet.Cells[i, 15].DisplayText, worksheet.Cells[i, 31].DisplayText));
values.Add((int)worksheet.Cells[i, 32].Value.NumericValue);
}
}
var mydic = new Dictionary<string, int>();
for (int i = 0; i < keys.Count; i++)
{
if (mydic.ContainsKey(keys[i]))
{
mydic[keys[i]] += values[i];
}
else
{
mydic.Add(keys[i], values[i]);
}
}
foreach (var item in mydic.Keys)
{
keys.Add(item);
}
foreach (var item in mydic.Values)
{
values.Add(item);
}
for (int i = 0; i < mydic.Count; i++)
{
string text = keys[i];
string[] rewrite = text.Split(',');
workbook.Worksheets[_sheetName].Cells[i, 0].SetValue(rewrite[0]);
workbook.Worksheets[_sheetName].Cells[i, 1].SetValue(rewrite[1]);
workbook.Worksheets[_sheetName].Cells[i, 2].SetValue(rewrite[2]);
workbook.Worksheets[_sheetName].Cells[i, 3].SetValue(rewrite[3]);
workbook.Worksheets[_sheetName].Cells[i, 4].SetValue(rewrite[4]);
}
for (int i = 0; i < mydic.Count; i++)
{
int text = values[i];
workbook.Worksheets[_sheetName].Cells[i, 5].SetValue(text);
}
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
IWorkbook workbook = spreadsheetControl.Document;
Worksheet worksheet = workbook.Worksheets["DataSet1"];
if (worksheet.HasData)
{
if (spreadsheetBarController1.Control.InvokeRequired)
{
spreadsheetBarController1.Control.Invoke((Action)delegate { CreateSheet("Summarized"); });
spreadsheetBarController1.Control.Invoke((MethodInvoker)delegate { ClearSheet("Summarized"); });
spreadsheetBarController1.Control.Invoke((Action)delegate { FillCell("Summarized"); });
}
}
else
{
MessageBox.Show("خطای داده ورودی", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
progressPanel1.Visible = false;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressPanel1.Visible = true;
}
}
|
|
|
|
|
Yes it will.
Because you have moved all of the code that processes stuff back to the UI thread by invoking it.
That's what Invoke does - it moves execution to the UI thread so that controls can be accessed.
What you are supposed to do is do the work on the BackgroundWorker, and pass the result for display to the UI thread via a progress report, not start a second thread and then invoke it all back onto the main thread. Do you not understand threading at all?
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
modified 12-Feb-21 8:45am.
|
|
|
|
|
I made some changes in my code. I used datatable for filling spreadsheet. I tried to pass UI related works (filling cells) to ProgressChanged event.
But it still freezes when filling spreadsheet.
private void barButtonItem5_ItemClick(object sender, ItemClickEventArgs e)
{
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
}
private void CreateSheet(string _sheetName)
{
IWorkbook workbook = spreadsheetControl.Document;
if (workbook.Worksheets.Contains(_sheetName) == false)
{
workbook.Worksheets.Add().Name = _sheetName;
}
}
private void ClearSheet(string _sheetName)
{
IWorkbook workbook = spreadsheetControl.Document;
var keys = new List<string>();
var values = new List<int>();
Worksheet ws_summarized = workbook.Worksheets[_sheetName];
ws_summarized.Clear(workbook.Worksheets[_sheetName].GetUsedRange());
keys.Clear();
values.Clear();
}
DataTable my_table = new DataTable();
DataTable my_table2 = new DataTable();
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
IWorkbook workbook = spreadsheetControl.Document;
Worksheet worksheet = workbook.Worksheets["DataSet1"];
CellRange range = worksheet.GetDataRange();
int LastRow = range.BottomRowIndex;
var keys = new List<string>();
var values = new List<int>();
for (int i = 0; i < LastRow + 1; i++)
{
if (worksheet.Cells[i, 10].DisplayText == "خاتمه یافته")
{
keys.Add(string.Join(",", worksheet.Cells[i, 28].DisplayText, worksheet.Cells[i, 0].DisplayText, worksheet.Cells[i, 9].DisplayText,
worksheet.Cells[i, 15].DisplayText, worksheet.Cells[i, 31].DisplayText));
values.Add((int)worksheet.Cells[i, 32].Value.NumericValue);
}
}
if (worksheet.HasData)
{
if (spreadsheetBarController1.Control.InvokeRequired)
{
spreadsheetBarController1.Control.Invoke((Action)delegate { CreateSheet("Summarized"); });
spreadsheetBarController1.Control.Invoke((MethodInvoker)delegate { ClearSheet("Summarized"); });
}
var mydic = new Dictionary<string, int>();
for (int i = 0; i < keys.Count; i++)
{
if (mydic.ContainsKey(keys[i]))
{
mydic[keys[i]] += values[i];
}
else
{
mydic.Add(keys[i], values[i]);
}
}
keys.Clear();
values.Clear();
foreach (var item in mydic.Keys)
{
keys.Add(item);
}
foreach (var item in mydic.Values)
{
values.Add(item);
}
my_table.Columns.Add("A");
my_table.Columns.Add("B");
my_table.Columns.Add("C");
my_table.Columns.Add("D");
my_table.Columns.Add("E");
for (int i = 0; i < mydic.Count; i++)
{
string text = keys[i];
string[] rewrite = text.Split(',');
my_table.Rows.Add(rewrite[0], rewrite[1], rewrite[2], rewrite[3], rewrite[4]);
}
my_table2.Columns.Add("F");
for (int i = 0; i < mydic.Count; i++)
{
int text = values[i];
my_table2.Rows.Add(text);
}
backgroundWorker1.ReportProgress(100);
}
else
{
MessageBox.Show("خطای داده ورودی", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
progressPanel1.Visible = false;
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
IWorkbook workbook = spreadsheetControl.Document;
Worksheet worksheet = workbook.Worksheets["DataSet1"];
CellRange range = worksheet.GetDataRange();
int LastRow = range.BottomRowIndex;
for (int i = 0; i < my_table.Rows.Count; i++)
{
workbook.Worksheets["Summarized"].Cells[i, 0].SetValue(my_table.Rows[i]["A"].ToString());
workbook.Worksheets["Summarized"].Cells[i, 1].SetValue(my_table.Rows[i]["B"].ToString());
workbook.Worksheets["Summarized"].Cells[i, 2].SetValue(my_table.Rows[i]["C"].ToString());
workbook.Worksheets["Summarized"].Cells[i, 3].SetValue(my_table.Rows[i]["D"].ToString());
workbook.Worksheets["Summarized"].Cells[i, 4].SetValue(my_table.Rows[i]["E"].ToString());
}
}
|
|
|
|
|
If you want to work with the UI-Control (as Griff mentioned) you have to use Invoke - there are a lot of samples for this inside the Internet.
Your other problem could be solved if you first look if the Backgroundworker is allready busy before you start it ...
|
|
|
|
|
I make change the following code:
if (!backgroundWorker1.IsBusy)
{
backgroundWorker1.RunWorkerAsync();
}
Now, The following runtime error occurs:
"System.InvalidOperationException: 'Cross-thread operation not valid: Control '' accessed from a thread other than the thread it "
The error is in line
workbook.Worksheets.Add().Name = "Summarized";
How to fix this?
|
|
|
|
|
Can you please give me links containing some practical examples of Invoke?
I searched Internet but all were about delegates. I don't know how to use Invoke and solve my problem.
|
|
|
|
|
Here is a very good Article: Invalid cross-thread operations[^]. In its first appendix, it presents a simple BackGroundWorker example.
However, you probably don't need to Invoke at all:
- do NOT touch Controls inside DoWork
- set your Controls the way you want them just before starting the BGW (e.g. disable a Button and/or show a ProgressBar)
- use the progress event handler to report progress, where you are allowed to touch Controls
- use the completed event to re-adjust Controls (e.g. re-enable a Button and/or hide a ProgressBar).
That's it; no Invoke at all.
And then, don't try to re-use a BackGroundWorker. If you have another background job, just create and set-up a new BackGroundWorker; they aren't expensive and they use pooled threads (from the ThreadPool).
Luc Pattyn [My Articles]
If you can't find it on YouTube try TikTok...
modified 10-Feb-21 16:27pm.
|
|
|
|
|
If you look at the DoWork section of my code, you see there are some operations which deals with GUI. For example creating a new sheet or filling data in cells or showing up message box. The order of those lines (in DoWork section) is necessary to have correct result. Now, I don't know how to revise my code to avoid cross threading. Most of my code lines have relationship with GUI.
|
|
|
|
|
Invoke is explained well in the article I provided. However:
If the big calculation (how long would it take on the GUI thread anyway?) is accessing a GUI Control all the time, then it makes little sense to delegate that to another thread, as you would need lots of Invoke operations (much code and much delay, switching a thread for just a few lines of calculations is silly).
There are two other approaches possible:
1. Use a DataTable of a DataSet; load those with the data, perform your calculations on them, then (re)display them somehow. I'm not familiar with the DevExpress sheet, I assume it knows how to display (or bind) to a DataTable. So you could show the original data, start computations in BGW, and have it pass the new state of the DataTable say every second, so the user sees progress (assuming it all takes several seconds, can't tell from what you have shown).
If you use binding (I don't!), chances are you must undo the bind before and redo it after the big computation (and also redo and undo it if relevant in progress handling).
2. Second alternative, very simple: Do everything on the GUI thread, start by showing a WaitCursor (so user knows and accepts he is not in charge for some time), then do what you want; if you want the user to see progress, call the Refresh method of the Control of interest (e.g. a ProgressBar); be careful to do that sporadically (say after dealing with 10 or 100 rows, roughly once a second would be enough), otherwise the execution will be extremely slow.
FYI: MessageBox is thread-safe, you can always call it, whatever thread you're on.
PS: No, I haven't read anything in your description that would warrant more than one BGW (or one extra thread).
Luc Pattyn [My Articles]
If you can't find it on YouTube try TikTok...
|
|
|
|
|
Thank you. That was helpful. I tried what you mentioned. I directed all my final results into a datatable and then, used an assembly to bind datatable to cells. The total calculation takes less than a second now. Thank you very much.
|
|
|
|
|
Thank you for the feedback.
Luc Pattyn [My Articles]
If you can't find it on YouTube try TikTok...
|
|
|
|
|
|
Research the invoke pattern. It is well documented, and required if you want to access UI components from a thread.
And we have plenty of articles on CP explaining that concept.
Bastard Programmer from Hell
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
Hello. I'm fairly new in C# .NET development, but I got a task to monitor data from the sensors using C# desktop application. I'm using ESP8266 to collect data from the sensors and I can send the data from the ESP to a remote MySQL database. I am free to graph the data obtained, using HTML, Javascript (Highcharts) and CSS - everything works fine. But now I have to display the received data from the ESP8266 in the windows desktop app remotely. Maybe someone could point me in the right direction? Thank you very much for the answers.
|
|
|
|
|
What have you tried?
Where are you stuck?
What help do you need?
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I really don't know where to start. I don't know what things are used for this purpose. I know a TCP client is used for similar things in C#.
|
|
|
|
|
Is the "remote" MYSQL db on the same device as the "remote" Windows desktop app?
If it is, have the Windows app retrieve the (time stamped) data it needs.
Even if it isn't, since you know how to send to a remote MySQL db, I assume you should be able to read / poll it remotely also.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
Hello Friends,
I have a requirement and would like to know how to code for this in C#.net:
I receive two files, one in BAI2 format and one in AMI format.
1.) How do I take AMI formatted file and convert it into BAI2 format file?
2.) How to do edit BAI2 file to add a unique identifier at the end of each line in the file.
I have installed Visual studio 2019.
TIA.
Sasi
|
|
|
|
|
There is no shortcut: you will need to learn to read AMI format: Amazon Machine Image - Wikipedia[^] and BA12 format: BAI2 Format Specification - SEPA for Corporates[^] and then write a reader for one, and a writer for the other. Then you need to work out what parts of your AMI document you need to access and store as BA12, because from what I can see the two are completely unrelated ...
Good luck with that: AMI format does not look like fun to process at all!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
I had a class ClusterHazardLocations which inherited some levels down from IEnumerable<IHazardLocation> . In case of an alarm, an AlarmInfo object is transferred from a sensor device via WCF to some other computer showing the information to the user. That AlarmInfo has an IHazardLocations property, and in this case it was a ClusterHazardLocations object. It used to work.
Then I added a simple function to that ClusterHazardLocations class: public void Add(IHazardLocation other) . The mere existence of the function - even with an empty body - causes the WCF communication to fail. I do not understand that at all. After all, IEnumerable does not have an Add method and the class does not derive from a List or similar base class.
After renaming the Add method to AddHazardLocation , everything worked again.
Could you please explain how this odd behavior of WCF was caused?
Edit:
"a small project" with WCF... Ehm. But a small interface /class hierarchy:
public interface IHazardLocation {}
public interface IHazardLocations : IEnumerable<IHazardLocation> {}
public interface IClusterHazardLocations : IHazardLocations { }
[Serializable]
public class ClusterHazardLocation : IClusterHazardLocation
{
public ICluster Cluster { get; }
[UsedImplicitly]
public ClusterHazardLocation()
{ }
public ClusterHazardLocation(ICluster _cluster)
: this()
{
Cluster = _cluster;
}
}
[Serializable]
public class ClusterHazardLocations : IClusterHazardLocations
{
[NotNull]
private readonly List<IClusterHazardLocation> m_Locations;
public ClusterHazardLocations()
{
m_Locations = new List<IClusterHazardLocation>();
}
public ClusterHazardLocations([NotNull] params IClusterHazardLocation[] _locations)
{
m_Locations = _locations.ToList();
}
public ClusterHazardLocations([NotNull] IEnumerable<IClusterHazardLocation> _locations)
{
m_Locations = _locations.ToList();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<IHazardLocation>)m_Locations).GetEnumerator();
}
public IEnumerator<IHazardLocation> GetEnumerator()
{
return ((IEnumerable<IHazardLocation>)m_Locations).GetEnumerator();
}
public void AddHazardLocation(IHazardLocation _other)
{
if (_other is IClusterHazardLocation tmp)
{
m_Locations.Add(tmp);
}
}
}
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
modified 8-Feb-21 10:12am.
|
|
|
|
|
Is this something you can recreate with a simple dummy project? If it's something you could upload to github, I'd enjoy having a look at it.
|
|
|
|
|
Thanks for your help. Unfortunatey, it's too big...
Do you have some similar situation some where:
- a class which inherits IEnumberable, but does not derive from List/Array etc, instead contains a List
- can be transferred via WCF
- now add an "Add" method
I am not sure if those are already all the required steps.
Oh sanctissimi Wilhelmus, Theodorus, et Fredericus!
|
|
|
|
|
I meant a simple repro of the issue rather than the thing itself.
|
|
|
|
|
What Pete is suggesting is a dummy project to prove where the fault lies: create a minimal sample that doesn't have the problem, add the Add method and see if it fails. If it does, put it up on Github for examination.
If it doesn't ... then the Add addition is probably coincidental, and you broke something else at the same time!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|