I know this has been asked many times, but I tried all solutions I found and no one works for me.
I have the following code:
public async void setFile(QuickBrowseFile file) {
try {
LoggingDatabaseService db = new LoggingDatabaseService();
LoggingData data = await db.getLoggingData(file.Id);
db.close();
if (data != null) {
List<LoggingModel> loggingData = data.RowData;
int numRows = loggingData.Count;
Application.Current.Dispatcher.Invoke((Action)(delegate {
for (int i = 0; i < numRows; i++) {
LoggingModel m = loggingData[i];
treeView.Items.Add(m);//!!!!!!!!!!!!exception here
}
}));
}
} catch (Exception ex) {
Logger.error(ex);
}
}
I tried a different solution, but problem is that I have a gif image that shows some frames using the solution from How do I get an animated gif to work in WPF?.
Using the code below doesn't throw any exception, but block the gif image while loading..
var uiContext = TaskScheduler.FromCurrentSynchronizationContext();
await Task.Factory.StartNew(() => {
LoggingDatabaseService db = new LoggingDatabaseService();
//Console.WriteLine(file.Id);
LoggingData data = db.getLoggingData(file.Id);
db.close();
if (data != null) {
List<LoggingModel> loggingData = data.RowData;
int numRows = loggingData.Count;
for (int i = 0; i < numRows; i++) {
treeView.Items.Add(loggingData[i]);
}
}
}, CancellationToken.None, TaskCreationOptions.None, uiContext);
Related
I have the code below for scanning but When i press the button to start scanning, the windows form freezes and i can not move the form or minimizie/colse it until the process will be finished! i'm new in working with Thread but i tried to add Thread andi couldn't solve the problem.
Does anyone know to where (how) can i write a Thread to release my form from freezing?
Thanks.
public Bitmap GetBitmapFromRawData(int w, int h, byte[] data)
{
//Do sth
}
//button to start the scan proccess
private void button1_Click(object sender, EventArgs e)
{
try
{
var deviceManager = new DeviceManager();
for ( int i = 1; i <= deviceManager.DeviceInfos.Count; i++ )
{
if ( deviceManager.DeviceInfos[i].Type != WiaDeviceType.ScannerDeviceType )
{
continue;
}
lstListOfScanner.Items.Add(deviceManager.DeviceInfos[i].Properties["Name"].get_Value());
}
}
catch ( COMException ex )
{
MessageBox.Show(ex.Message);
}
try
{
var deviceManager = new DeviceManager();
DeviceInfo AvailableScanner = null;
for ( int i = 1; i <= deviceManager.DeviceInfos.Count; i++ )
{
if ( deviceManager.DeviceInfos[i].Type != WiaDeviceType.ScannerDeviceType ) // Skip device If it is not a scanner
{
continue;
}
AvailableScanner = deviceManager.DeviceInfos[i];
break;
}
var device = AvailableScanner.Connect();
var ScanerItem = device.Items[1];
var imgFile = (ImageFile)ScanerItem.Transfer();
var data = (byte[])imgFile.FileData.get_BinaryData();
var bitmap = GetBitmapFromRawData(imgFile.Width, imgFile.Height, data);
var Path = #"C:\....\ScanImg.jpg";
bitmap.Save(Path, ImageFormat.Jpeg);
}
catch ( COMException ex )
{
MessageBox.Show(ex.Message);
}
Try adopting the async/await approach:
private async void button1_Click(object sender, EventArgs e)
{
try
{
object[] items = await Task.Run<object[]>(() =>
{
var deviceManager = new DeviceManager();
List<object> result = new List<object>();
for (int i = 1; i <= deviceManager.DeviceInfos.Count; i++)
{
if (deviceManager.DeviceInfos[i].Type != WiaDeviceType.ScannerDeviceType)
{
continue;
}
result.Add(deviceManager.DeviceInfos[i].Properties["Name"].get_Value());
}
return result.ToArray();
});
foreach (var item in items)
{
lstListOfScanner.Items.Add(item);
}
}
catch (COMException ex)
{
MessageBox.Show(ex.Message);
}
try
{
await Task.Run(() =>
{
var deviceManager = new DeviceManager();
DeviceInfo AvailableScanner = null;
for (int i = 1; i <= deviceManager.DeviceInfos.Count; i++)
{
if (deviceManager.DeviceInfos[i].Type != WiaDeviceType.ScannerDeviceType) // Skip device If it is not a scanner
{
continue;
}
AvailableScanner = deviceManager.DeviceInfos[i];
break;
}
var device = AvailableScanner.Connect();
var ScanerItem = device.Items[1];
var imgFile = (ImageFile)ScanerItem.Transfer();
var data = (byte[])imgFile.FileData.get_BinaryData();
var bitmap = GetBitmapFromRawData(imgFile.Width, imgFile.Height, data);
var Path = #"C:\....\ScanImg.jpg";
bitmap.Save(Path, ImageFormat.Jpeg);
});
}
catch (COMException ex)
{
MessageBox.Show(ex.Message);
}
}
I’ve created a user control. In the control I have two methods – sending and receiving some data. Those methods also update the data grid located on the user control.
public void RunTX()
{
tx_run = new Thread(new ThreadStart(SendCanFrames));
if (!tx_run.IsAlive)
{
tx_run.IsBackground = true;
tx_run.Start();
}
}
public void RunRX()
{
rx_run = new Thread(new ThreadStart(ReadCanFrames));
if (!rx_run.IsAlive)
{
rx_run.IsBackground = true;
rx_run.Start();
}
}
private void ReadCanFrames()
{
ushort prev_time_stamp = 0;
while (running)
{
if (CanDevice != null)
CanDevice.Read(ref rx_can_msg, 1, ref read_cnt);
if (read_cnt == 1)
{
read_cnt = 0;
dataGridViewCanRx.Rows[0].Cells[0].Value = rx_can_msg[0].Id.ToString("X");
dataGridViewCanRx.Rows[0].Cells[1].Value = rx_can_msg[0].Size.ToString();
dataGridViewCanRx.Rows[0].Cells[2].Value = BytesToString(rx_can_msg[0].Data);
dataGridViewCanRx.Rows[0].Cells[3].Value = (rx_can_msg[0].TimeStamp - prev_time_stamp).ToString();
prev_time_stamp = rx_can_msg[0].TimeStamp;
}
prev_time_stamp = rx_can_msg[0].TimeStamp;
}
}
private void SendCanFrames()
{
if (tx_can_msg.Length == 0) return;
VSCAN_MSG[] l_msgs = new VSCAN_MSG[2];
while (running)
{
for (int i = 0; i < tx_can_msg.Length; i++)
{
if (can_messages[i].CountRun < can_messages[i].CountMax)
{
can_messages[i].TimeStamp1 = DateTime.Now;
interval = can_messages[i].TimeStamp1 - can_messages[i].TimeStamp2;
if (interval.TotalMilliseconds >= can_messages[i].Period)
{
can_messages[i].TimeStamp2 = DateTime.Now;
l_msgs[0] = tx_can_msg[i];
//send CAN frame
CanDevice.Write(l_msgs, 1, ref written_cnt);
// send immediately
CanDevice.Flush();
can_messages[i].CountRun++;
dataGridViewCanTx.Rows[i].Cells[4].Value = can_messages[i].CountRun.ToString();
}
}
}
}
}
I put four user control instances on the main form and start all four controls.
private void buttonStartAll_Click(object sender, EventArgs e)
{
int can_channel;
for (can_channel = 0; can_channel < 4; can_channel++)
{
if (started[can_channel] == false)
{
if (connected[can_channel] == true)
{
switch (can_channel)
{
case 0:
mainform.userControlCan1.RunTX();
mainform.userControlCan1.RunRX();
started[can_channel] = true;
break;
case 1:
mainform.userControlCan2.RunTX();
mainform.userControlCan2.RunRX();
started[can_channel] = true;
break;
case 2:
mainform.userControlCan3.RunTX();
mainform.userControlCan3.RunRX();
started[can_channel] = true;
break;
case 3:
mainform.userControlCan4.RunTX();
mainform.userControlCan4.RunRX();
started[can_channel] = true;
break;
}
}
}
}
}
All is running, however the GUI freezing and data grids updated by jumps. Why?
I recomend you to look at two key points: Invoke and Application.DoEvents.
First one will help you to update your GUI in main thread instead of child threads.
Have a look at : https://learn.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.invoke?view=netframework-4.8
Application.DoEvents() method tells the system to do other waiting jobs without blocking in some loops. Otherwise updating GUI jobs are postponed and GUI is blocked. Here is the information about this method: https://learn.microsoft.com/tr-tr/dotnet/api/system.windows.forms.application.doevents?view=netframework-4.8
private delegate void dlgUpdateRows(object[] rx_can_msg, int tID);
// Write actual type of rx_can_msg instead of object[] in method signature , second parameter should be your thread id if needed
private void UpdateRows(object[] rx_can_msg, int tID =0)
{
try
{
if (this.InvokeRequired)
{
object[] obj = new object[2];
obj[0] = rx_can_msg;
obj[1] = Thread.CurrentThread.ManagedThreadId;
this.Invoke(new dlgUpdateRows(UpdateRows), obj);
}
else
{
//Here update your datagrid using rx_can_msg
}
//This row is important to avoid blocking
Application.DoEvents();
}
catch (Exception ex)
{
//Do error handling
}
}
I've a basic form application. It displays a list of checkbox and a list of asyn task update CheckBox label :
public partial class Form1 : Form
{
List<CheckBox> checkedBoxes = new List<CheckBox>();
public Form1()
{
InitializeComponent();
CreateCheckBoxes();
Display();
}
public void CreateCheckBoxes()
{
SuspendLayout();
for (int i = 0; i < 11; i++)
{
checkedBoxes.Add(new CheckBox() {Name = "Combo"+i, Text = "-"+i });
flowLayoutPanel1.Controls.Add(checkedBoxes[i]);
}
ResumeLayout();
}
private async void Display()
{
List < Task < LyStruc >> tasks = new List<Task<LyStruc>>();
for (int i = 0; i < 10; i++)
{
tasks.Add(Task.Run(() => { return ProcessMessage(i); }) );
}
var wa = await Task.WhenAll(tasks.ToArray());
// Doesn't work (few checkbox update label)
foreach (LyStruc t in wa)
{
UpdateCheckBoxLabel(t);
}
// Doesn't work either.
//TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
//foreach (var item in tasks)
//{
// item.ContinueWith(c =>
// {
// switch (c.Status)
// {
// case TaskStatus.RanToCompletion: Test(c.Result); break;
// case TaskStatus.Faulted: richTextBox1.Text = c.Exception.ToString(); break;
// }
// }, taskScheduler);
// }
}
private void UpdateCheckBoxLabel(LyStruc s)
{
this.checkedBoxes[s.Id].Text = "Update" + s.Name;
}
private LyStruc ProcessMessage(int i)
{
return new LyStruc()
{
Id = i,
Name = string.Format( "-Combo {0}", i),
};
}
}
Why don't all checkboxes change (just few of them) ? I get no errors. I expect that each check box update with label CheckBox
The program uses two threads: one for collecting the data from USB, and the other writes/displays the data. It seems to work as expected, however, as soon as I minimize/restore any windows on the PC, or press any buttons on the Form, it stops working properly (it stops receiving data). I use link list to keep the data streaming in order. I suspect that maybe the link is lost somewhere because of improper variable declaration. Is there an obvious mistake in my code that could be causing this?
namespace Streamer
{
public class Form1 : System.Windows.Forms.Form
{
Thread tListen;
Thread tDisplay;
public class MY_DATA_BUFFER
{
public byte[] buffer;
public int length;
public MY_DATA_BUFFER nextBuff;
}
private Object thisLock = new Object();
MY_DATA_BUFFER pHead = null;
private static AutoResetEvent DataQueueEvent = new AutoResetEvent(false);
public Form1()
{
// some settings;
}
public unsafe void dataDisplayThread()
{
MY_DATA_BUFFER pWorkingSet = pHead;
if (pWorkingSet == null)
{
// Make sure link list head is initialized...........
do {DataQueueEvent.WaitOne();} while (pHead == null);
// Wait till the two datas are available to write.
if (pHead.nextBuff == null){ DataQueueEvent.WaitOne(); }
if (pWorkingSet == null) { pWorkingSet = pHead; }
}
// Let's start the data write loop
while (bRunning || (pWorkingSet != null))
{
// copy small array to a bigger array
for (int i = 0; i < pWorkingSet.length; i++)
{
pixelValues[pixptr] = pWorkingSet.buffer[i];
pixptr++;
}
if (pixptr >= imWidth * imHeight)
{
pixptr = 0;
// show data in pixelValues
}
// Traverse through the link list data structure.
if (pWorkingSet.nextBuff == null)
{
do
{
if (pWorkingSet.nextBuff == null DataQueueEvent.WaitOne();
lock (thisLock)
{
if (pWorkingSet.nextBuff == null && !bRunning)
break;
}
} while (pWorkingSet.nextBuff == null);
}
// We are good to loop for the next operation
lock (thisLock)
{
pHead = pHead.nextBuff;
pWorkingSet = pHead;
}
}
// All write operation is at completion
pHead = null;
}
public unsafe void XferData(...)
{
MY_DATA_BUFFER tempBuff = null;
for (; bRunning; )
{
// .... do something
// push the data to a link list for
lock (thisLock)
{
MY_DATA_BUFFER newBuff = new MY_DATA_BUFFER();
newBuff.nextBuff = null;
newBuff.buffer = xBufs[k];
newBuff.length = len;
if (tempBuff == null) tempBuff = newBuff;
else
{
tempBuff.nextBuff = newBuff;
tempBuff = newBuff;
}
if (pHead == null) pHead = newBuff;
else
{
DataQueueEvent.Set();
}
}
///////////////////Link List Population completes///////////
Thread.Sleep(0);
} // End infinite loop
}
private void StartBtn_Click(object sender, System.EventArgs e)
{
if (StartBtn.Text.Equals("Start"))
{
// ...
pHead = null;
bRunning = true;
tListen = new Thread(new ThreadStart(XferThread));
tListen.IsBackground = true;
tListen.Priority = ThreadPriority.Highest;
tListen.Start();
tDisplay = new Thread(new ThreadStart(dataDisplayThread));
tDisplay.IsBackground = true;
tDisplay.Priority = ThreadPriority.Highest;
tDisplay.Start();
}
else
{
if (tListen.IsAlive)
{
// ...
bRunning = false;
if (tListen.Join(5000) == false )
tListen.Abort();
tListen = null;
}
if (tDisplay.IsAlive)
{
if (tDisplay.Join(5000) == false )
tDisplay.Abort();
Display = null;
}
}
}
}
}
Boys and Girls,
I got this method (task) that gets executed when I select a node in a treeview. It retreives data from a database and puts in a ReportControl (Codejock).
What I need is to prevent that this method (task) gets executed again while it is still running.
I've been experimenting with booleans set to false when starts and set to true if finishes but that doesn't work for some reason.......
here is the code:
the event where the method gets executed:
private void tvObjects_AfterSelect(object sender, TreeViewEventArgs e)
{
try
{
tvObjects.PreseveTreeState = true;
tvObjects.SaveTreeState();
tvObjects.SelectedNode.BackColor = Color.FromArgb(191, 210, 234);
AllowPreview = false;
WordPreviewer.UnloadPreviewHandler();
viewer1.Image = null;
rcDocumenten.ClearContent();
rcEmail.ClearContent();
var n = e.Node as ExtendedTreeNode;
tvObjects.CurrentNode = e.Node;
SelectedObjectNode = n;
WordPreviewer.FileName = null;
if (n != null)
{
Document.SetDossierNummer(n.DossierNr);
}
var selNode = e.Node as ExtendedTreeNode;
if (selNode != null && selNode.DossierNode)
{
if (selNode.IsFolder)
{
DossierNr = Convert.ToInt32(selNode.DossierNr);
SelectedObjectNode = selNode;
var col = new col();
col.CreateCurrentDossierDocumentsList(Convert.ToInt32(selNode.DossierNr.ToString()),
selNode.Tag.ToString());
col.CreateCurrentEmailList(selNode.DossierNr, Convert.ToInt32(selNode.Tag.ToString()));
var t =
new Thread(
() =>
rcDocumenten_Populate(Convert.ToInt32(selNode.DossierNr.ToString()),
selNode.Tag.ToString()));
t.Start();
var t2 = new Thread(
() => rcEmail_Populate(selNode.DossierNr, Convert.ToInt32(selNode.Tag.ToString())));
t2.Start();
tcDocumenten.SelectedTab = selNode.Text.Contains("Email") ? tpEmail : tpDocumenten;
}
else
{
tpDocumenten.Text = #"Documenten (0)";
tpEmail.Text = #"Emails (0)";
SelectedBestandId = -1;
SelectedBestandsNaam = string.Empty;
SelectedEmailId = -1;
SelectedEmailOnderwerp = string.Empty;
}
}
else if (selNode != null && selNode.PersonalNode)
{
if (!selNode.IsMedewerker)
{
var t =
new Thread(
() => rcDocumenten_PersoonlijkeMappenPopulate(Convert.ToInt32(selNode.Tag.ToString())));
t.Start();
}
}
}
catch (InvalidOperationException iex)
{
MessageBox.Show(iex.ToString());
}
catch (Exception ex)
{
var dmsEx = new DmsException("Fout tijdens het uitvoeren event AfterSelect tvObjects ", "VDocumenten (tvObjects Event: AfterSelect)", ex);
ExceptionLogger.LogError(dmsEx);
}
}
the method that should not run twice:
public void rcDocumenten_PersoonlijkeMappenPopulate(int personalFolderId)
{
try
{
AllowPreview = false;
var oc = new col();
rcDocumenten.FocusedRow = null;
oc.CreateCurrentPersoonlijkeDocumentsList(personalFolderId);
UpdateUI(false);
if (rcDocumenten.InvokeRequired)
{
rcDocumenten.Invoke((MethodInvoker)delegate
{
rcDocumenten.Records.DeleteAll();
rcDocumenten.Redraw();
_gegevensLaden = new GegevensLaden(this);
_gegevensLaden.Show();
//Documenten uit Database ophalen
_gegevensLaden.progressbar.Maximum = col.ListPersoonlijkeDocuments.Count;
foreach (var document in col.ListPersoonlijkeDocuments)
{
var versie = Convert.ToDecimal(document.Versie.ToString());
if (document.OriBestandId == 0)
{
//Record toevoegen
rcDocumenten_Persoonlijk_AddRecord(document.BestandId, document.BestandsNaam, versie,
document.DatumToevoeg, document.DatumUitcheck, document.UitgechecktDoor, document.Eigenaar,
document.DocumentType, document.DocumentProgres);
}
_gegevensLaden.progressbar.Value = _gegevensLaden.progressbar.Value + 1;
_gegevensLaden.progressbar.Update();
}
var aantalRecords = 0;
for (var i = 0; i < rcDocumenten.Records.Count; i++)
{
aantalRecords++;
for (var j = 0; j < rcDocumenten.Records[i].Childs.Count; j++)
{
aantalRecords++;
}
}
tpDocumenten.Text = #"Documenten (" + aantalRecords + #")";
rcDocumenten.Populate();
Invoke(new UpdateUIDelegate(UpdateUI), new object[] { true });
});
}
//"dd-MM-yyyy HH:mm:ss"
AllowPreview = true;
}
catch (Exception ex)
{
var dmsEx = new DmsException("Fout bij de populatie van Report Control", "VDocumenten (rcDocumenten_Persoonlijk_Populate)", ex);
ExceptionLogger.LogError(dmsEx);
}
}
You can check if the thread/task has completed. Change the thread creation to use a Task
_t =
Task.Factory.StartNew(
() =>
rcDocumenten_Populate(Convert.ToInt32(selNode.DossierNr.ToString()),
selNode.Tag.ToString()));
Then you can keep the Task around in the class scope. As you see above, I called it _t.
private Task _t; // documenten vullen achtergrond thread
Now, instead of blindly starting the Task, check if the Task should be started.
if (_t == null || _t.IsCompleted) {
That would solve your current issue.