|
Message Closed
modified 13-Feb-21 8:00am.
|
|
|
|
|
|
Good morning I have a problem that is making me desperate. I want to deserelize a Json but the content is always null. I pass you my code, if you could give me a hand I would appreciate it very much.
Regards and thank you very much in advance.
CLASS
public class RootContactos
{
public string contacto { get; set; }
public string email { get; set; }
public string telefono { get; set; }
public string notas { get; set; }
}
CODE
contac = JsonConvert.DeserializeObject<rootcontactos>(strJson);
JSON
{"20150630140000#1":{"contacto":"PATRICIA","telefono":"976185823","email":"","notas":""},"20150630140001#1":{"contacto":"FAX","telefono":"976180364","email":"","notas":""}}
|
|
|
|
|
Your JSON does not match the class, which is probably why you get a problem. If I run your JSON through a class creator (Convert JSON to C# Classes Online - Json2CSharp Toolkit[^]) then what I get is three classes:
public class _201506301400001 {
public string contacto { get; set; }
public string telefono { get; set; }
public string email { get; set; }
public string notas { get; set; }
}
public class _201506301400011 {
public string contacto { get; set; }
public string telefono { get; set; }
public string email { get; set; }
public string notas { get; set; }
}
public class Root {
[JsonProperty("20150630140000#1")]
public _201506301400001 _201506301400001 { get; set; }
[JsonProperty("20150630140001#1")]
public _201506301400011 _201506301400011 { get; set; }
} Which is what I would expect from that: two different classes with identical content but different names!
I'd start by looking at the data source - I'd expect an array of JSON data containing two elements, not two individual items.
"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!
|
|
|
|
|
Thank you very much for answering. The classes that he proposes to me, I cannot perform them because the "header" (_201506301400001) varies in each record of the database.
I have been testing and I have managed to do the deserilization in this way:
var result = JsonConvert.DeserializeObject <dynamic> (strJson);
But then I have not gotten the information from resutl.
Regards and thank you very much in advance.
|
|
|
|
|
Deserialize it into a Dictionary.
void Main()
{
var json =@"{""20150630140000#1"":{""contacto"":""PATRICIA"",""telefono"":""976185823"",""email"":"""",""notas"":""""},""20150630140001#1"":{""contacto"":""FAX"",""telefono"":""976180364"",""email"":"""",""notas"":""""}}";
<pre>
var contacDict = JsonConvert.DeserializeObject<IDictionary<string,RootContactos>>(json);
contacDict.Values.First().Dump();
contacDict["20150630140001#1"].Dump();
}
public class RootContactos
{
public string contacto { get; set; }
public string email { get; set; }
public string telefono { get; set; }
public string notas { get; set; }
}</pre>
Truth,
James
|
|
|
|
|
Thank you very much it has worked perfectly.
Regards, and thank you very much.
|
|
|
|
|
I'm working on Devexpress Spreadsheet application. My calculation are as below:
1. Data is read from a sheet into two Lists. One list is string type and another is integer type. String type list consists of values of 4 cells in each row.
2. Lists are put into a dictionary. Strings are keys and integers are values.
3. Values of the same keys are summed.
4. The mentioned two lists are cleared and fill by dictionary keys and values.
5. Dictionary keys and values are split into cells in a new sheet.
I want to show progress animation (comes with DevExpress tools) when calculations begin. I used following code:
<pre lang="C#"> private void barButtonItem5_ItemClick(object sender, ItemClickEventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
IWorkbook workbook = spreadsheetControl.Document;
Worksheet worksheet = workbook.Worksheets.ActiveWorksheet;
CellRange range = worksheet.GetDataRange();
int LastRow = range.BottomRowIndex;
var keys = new List<string>();
var values = new List<int>();
progressPanel1.Visible = true;
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]);
}
}
if (worksheet.HasData)
{
if (workbook.Worksheets.Contains("Summarized") == false)
{
workbook.Worksheets.Add().Name = "Summarized";
}
Worksheet ws_summarized = workbook.Worksheets["Summarized"];
ws_summarized.Clear(workbook.Worksheets["Summarized"].GetUsedRange());
keys.Clear();
values.Clear();
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["Summarized"].Cells[i, 0].SetValue(rewrite[0]);
workbook.Worksheets["Summarized"].Cells[i, 1].SetValue(rewrite[1]);
workbook.Worksheets["Summarized"].Cells[i, 2].SetValue(rewrite[2]);
workbook.Worksheets["Summarized"].Cells[i, 3].SetValue(rewrite[3]);
workbook.Worksheets["Summarized"].Cells[i, 4].SetValue(rewrite[4]);
}
for (int i = 0; i < mydic.Count; i++)
{
int text = values[i];
workbook.Worksheets["Summarized"].Cells[i, 5].SetValue(text);
}
}
else
{
MessageBox.Show("خطای داده ورودی", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
When I run and press the dedicated button, the following runtime error occurs:
System.InvalidOperationException: 'Cross-thread operation not valid: Control 'spreadsheetFormulaBarPanel' accessed from a thread other than the thread it was created on.'
The error in in line
progressPanel1.Visible = true;
I tried to delete that line and check whether it works. This time the following runtime error occurred:
System.InvalidOperationException: 'This BackgroundWorker is currently busy and cannot run multiple tasks concurrently.'
This error occurs in line
backgroundWorker1.RunWorkerAsync();
PLEASE HELP ME.
|
|
|
|
|
You cannot access UI controls from any other thread than the original UI thread: if you try, you will cause a Cross Threading Exception.
So when you do this:
progressPanel1.Visible = true; in the BackgroundWorker DoWork event, you will immediately error the thread.
The BackgroundWorker includes progress reporting, which is automatically routed back to the UI thread so it is entirely safe to access controls from the ProgressChanged event[^]. But not from anywhere else!
"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!
|
|
|
|
|
Thanks. I wrote the code in ProgressChanged event.
What about the other runtime error? It still says:
"System.InvalidOperationException: 'This BackgroundWorker is currently busy and cannot run multiple tasks concurrently.'"
This error occurs in the line below:
backgroundWorker1.RunWorkerAsync();
|
|
|
|
|
A BackgroungWorker is a thread - if it's busy doing something, you can't start it again!
Normally, I create a BW, add the dowork and progress event handlers, then a BackgroundWorker.RunWorkerCompleted Event (System.ComponentModel) | Microsoft Docs[^] event which tells the main thread it's all done. If in the meantime I need another, I create one and go through the same process with that.
Don't recycle them: create one when you need it, use it and dispose it!
"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!
|
|
|
|
|
How many BW do I need in my example?
Do I need to add them from designing window?
|
|
|
|
|
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...
|
|
|
|
|
|