How to use Thread to release the application from freezing in c# - c#

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);
}
}

Related

WPF Must create DependencySource on same Thread as the DependencyObject

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);

Why i'm getting cross thread exception while updating label in backgroundworker progresschanged event?

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];

Program stops working after minimizing any window in Windows

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;
}
}
}
}
}

How to display a chart with XML data in Windows phone 8 Mvvm

I am making an app which hast to display currency rates by date from online XML.
I am using Sparrow Chart. When tested it with sample data, the chart displays data only when the GenerateDatas() method is called right in the ChartViewModel function but it is not displaying or refreshing when I call the function after asinc XML data read or with ICommand.
List<CurrencyOfDate> list = new List<CurrencyOfDate>();
foreach (XElement c in xmlData.Elements(ns + "Cube").Elements(ns + "Cube"))
list.Add(new CurrencyOfDate()
{
Date = c.Attribute("time").Value,
CurrencyTypes = (from k in xmlData.Elements(ns + "Cube").Elements(ns + "Cube").Elements(ns + "Cube")
select new CurrencyType()
{
Name = k.Attribute("currency").Value,
Value = k.Attribute("rate").Value
}).ToList()
});
FeatList = list;
if (FeatList != null)
{
foreach (var date in FeatList)
{
var x = DateTime.Parse(date.Date);
PickedDate.Add(x);
}
for (int i = 0; i < FeatList.Count; i++)
{
CurList = FeatList[i].CurrencyTypes.ToList();
}
}
MakeChartData();
}
private void MakeChartData()
{
try
{
IsDataLoading = true;
for (int i = 0; i < CurList.Count; i++)
{
var selectedCurrencyRates =
(from c in CurList where c.Name == "GBP" select c).ToList();
foreach (var selRate in selectedCurrencyRates)
{
double parsedFromValue = Double.Parse(selRate.Value);
CalculatedRate.Add(parsedFromValue);
}
}
GenerateDatas();
}
catch (Exception e)
{
IsDataLoading = false;
}
Refresh();
}
private void GenerateDatas()
{
Refresh();
try
{
IsDataLoading = true;
this.Collection.Add(new Model(PickedDate[0], CalculatedRate[0]));
this.Collection.Add(new Model(PickedDate[10], CalculatedRate[10]));
this.Collection.Add(new Model(PickedDate[20], CalculatedRate[20]));
this.Collection.Add(new Model(PickedDate[30], CalculatedRate[30]));
IsDataLoading = false;
}
catch (Exception ex)
{
IsDataLoading = false;
}
}
And xaml:
<chart:SparrowChart x:Name="Chart1" Height="409" Margin="0,0,22,0">
<chart:SparrowChart.Legend>
<chart:Legend Header="EUR/GBP" Height="55" Margin="155,0,172,4" Width="107" />
</chart:SparrowChart.Legend>
<chart:SparrowChart.DataContext>
<viewModels:ChartViewModel/>
</chart:SparrowChart.DataContext>
<chart:SparrowChart.XAxis>
<chart:LinearXAxis/>
</chart:SparrowChart.XAxis>
<chart:SparrowChart.YAxis>
<chart:LinearYAxis/>
</chart:SparrowChart.YAxis>
<chart:LineSeries PointsSource="{Binding Collection}" XPath="X" YPath="Y" IsRefresh="True"/>
</chart:SparrowChart>
The problem is solved. This code works. The problem was that Collection was List type but it should be ObservableCollection.

Prevent task being executed again while it is still running

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.

Categories