I am working on a project where I am implementing a SaveSettings method which saves lot of settings to a xml file.
Problem is it takes time to do that, that's why when I click Save button on my form my UI just hangs/stops for a while.
The method looks like below
public void SaveSettings(SettingsType settingsType)
{
if (!File.Exists(_settingsFile))
{
File.Create(_settingsFile);
}
var xmlDoc = XDocument.Load(_settingsFile);
switch (settingsType)
{
case SettingsType.Measurement:
SaveMeasurementSettings(ref xmlDoc);
break;
case SettingsType.Display:
SaveDisplaySettings(ref xmlDoc);
break;
case SettingsType.Common:
SaveCommonSettings(ref xmlDoc);
break;
case SettingsType.View:
SaveViewSettings(ref xmlDoc);
break;
case SettingsType.InputChannel:
SaveInputChannelSettings(ref xmlDoc);
break;
default:
break;
}
xmlDoc.Save(_settingsFile);
}
I want to make SaveSettings method asynchronous something BeginSave/EndSave so that when I call BeginSave my UI should go smooth. I have no BackgroundWorker as I am using .Net Compact Framework.
Any guidance on implementing Asynchronous pattern please...
The Save() of XDocument can be implemented as:
public void Save(string xmlFilePath)
{
Thread thread = new Thread(new ParameterizedThreadStart(SaveSettings));
thread.Start(xmlFilePath);
}
private void SaveSettings(object data)
{
string xmlFilePath;
if ((xmlFilePath = data as string) != null)
{
this.SaveSettingsFile(xmlFilePath);
}
}
private void SaveSettingsFile(string xmlFilePath)
{
// Save the file contents
}
The simplest way is using .Net Thread
Take a look at the accepted answer on this post. You could also use reflector and grab the code for the BackgroundWorker class if you wanted. Here is an implementation of it to get you started.
There is also an article on MSDN about this: Microsoft .NET Compact Framework Background Processing Techniques
If you're on .Net 4 (or newer), consider using Tasks. They're an easier way to deal with asynchronous behavior that you're spinning up.
I have tried to put together a simplistic implementation. It is untested. Also instead of using a Thread see if you can use a ThreadPool thread in the compact framework. Hope it helps.
public class SettingsType {}
public class Settings
{
private Thread _worker;
public void SaveSettings(SettingsType type)
{
// save logic
}
public void BeginSaveSettings(SettingsType type)
{
_worker = new Thread(() => SaveSettings(type)) {IsBackground = true};
_worker.Start();
}
public bool EndSaveSettings(TimeSpan timeOut)
{
return _worker.Join(timeOut);
}
}
Related
I am building a command-line exe that can apply several operations on a PDF file (add text, images, resize, crop, etc).
Currently, my Program.cs looks a bit like this (it uses CommandLineParser):
switch (invokedVerb)
{
case "barcode":
Operations.BarcodeOperations.AddBarCode(options.AddBarcodeVerb);
break;
case "addblankpage":
Operations.PageOperations.AddBlankPage(options.AddBlankPageVerb);
break;
}
As you can see, I have split the operations into several XXXOperations classes, each of them having very similar instructions:
public static void AddStuff(StuffOptions options)
{
Logging.Log("here is a bunch of logging");
// here sometimes there is some action-specific code but not often
using (DocWrapper doc = new DocWrapper(options.File)) // this is in all actions
{
foreach (int page in doc.GetPagesToModify(options.Pages)) // this is in most actions
{
// call some stuff on the doc instance
}
doc.Save(options.OutputFile); // this is in all actions
}
}
So, all actions create a new instance of DocWrapper, most of them loop on its pages (but I could modify the actions so that all of them do), and all of them save, but each of them do a different set of actions inside it.
How could I refactor this code so that the DocWrapper instantiation, the pages loop and the save are in a single place, but I can specify custom code inside the loop ?
I'm thinking of using delegates or Actions to define my actions, but I have no idea where to start, since I'm not very familiar with them.
Thanks!
I have found a solution and posted it at CodeReview
Here is what I have done so far:
I have created a Worker class with my redundant code:
public static void DoWorkOnPages(IProgramOptions options, Action<DocWrapper, int> actions)
{
using (DocWrapper doc = new DocWrapper(options.File))
{
foreach (int page in doc.GetPagesToModify(options.Pages).OrderBy(p => p))
{
actions(doc, page);
}
doc.Save(options.OutputFile);
}
}
And in each XXXOperations class my methods calls it like this:
public static void AddBarStuff(StuffOptions options)
{
Logging.Log("Here is a magnificient function");
using (Image barcode = CreateStuffImage(someParameters))
{
Worker.DoWorkOnPages(options, (doc, page) =>
{
// do something with options, doc, page and barcode
});
}
}
Obviously, for in the operations that do not quite exactly work like
this, I had to duplicate some code, but I guess it can't be helped.
If you come up with a more elegant, more simple, more powerful
solution or just a different one, I'll gladly upvote it.
I'm using an external library load a large and complex file. The call(s) to this library are fairly complex, so I've wrapped them in a couple of static helper methods which nicely take care of caching etc. for me. These methods are then run in the background using Tasks.
During the load process, the library will in some cases throw an Exception stating that a block of the file is malformed and therefore cannot be parsed. These Exceptions are considered "safe", and, if they're swallowed, the library will skip the bad block and happily continue to parse the rest of the file.
When this occurs, I need to show the user a dialog box asking whether or not the file import should be aborted. This works fine as follows:
public static class MyBigFileLoadMethods {
// private fields for locking, caching, etc.
public static Load(string filePath, bool cache = true) {
// validation etc.
try {
var data = LoadMethodInDll(filePath);
} catch (BadBlockException) {
if (MessageBox.Show("boom. continue anyway?") == DialogResult.Yes) {
// call appropriate dll methods to ignore exception and continue loading
} else {
throw;
}
}
}
}
Calling MessageBox.Show() from a method that was designed to be run way in the background feels very wrong, but I haven't come up with a better way that didn't involve so much marshaling and invoking that the code became very difficult to read. Is there a cleaner way to do this or a better way to me to design my loading process?
The appropriate way for a library to do this is via some kind of callback. The simplest implementation would be a delegate returning a bool indicating whether processing should continue. A richer but complicated way would be a policy interface with various methods to implement indicating whether to continue, abort, retry, etc.
Then your UI code provides the callback that shows a message to the user in an appropriate way. Your code to load the library will look like this:
public static class MyBigFileLoadMethods {
// private fields for locking, caching, etc.
public static void Load(string filePath, Func<Exception, bool> continueOnException = null, bool cache = true) {
// validation etc.
try {
var data = LoadMethodInDll(filePath);
} catch (BadBlockException e) {
if (continueOnException != null && continueOnException(e)) {
// call appropriate dll methods to ignore exception and continue loading
} else {
throw;
}
}
}
}
Then in your UI code you will want to marshal back to the UI thread. It will look something like this:
MyBigFileLoadMethods.Load("C:\path\to\data", ShowError);
private bool ShowError(Exception e)
{
if (this.InvokeRequired)
{
return (bool)this.Invoke(new Func<Exception, bool>(ShowError), e);
}
return MessageBox.Show(string.Format("boom: {0}. continue anyway?", e.Message)) == DialogResult.Yes;
}
I am having a RichTextbox and I am trying to save file using
public bool SaveNote(string path)
{
try
{
_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText);
return true;
}
catch
{
return false;
}
}
It was working fine until I started working with background worker thread. Now this method is being called from background worker and now I am receiving an error as
Cross-thread operation not valid: Control 'rtbContent' accessed from a thread other than the thread it was created on.
I think we have to invoke it using _rtbContent.Invoke but failing to get the syntax correct. What I tried was
if(_rtbContent.InvokeRequired)
_rtbContent.Invoke(new MethodInvoker(_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText)));
Here I am getting Method name expected compilation error on _rtbContent.SaveFile(path, RichTextBoxStreamType.RichText).
I am not very comfortable in using these threads but has recently started working on them. Can anyone help me on this issue?
Use a callback:
delegate void SaveNoteCallback(string path);
public void SaveNote(string path)
{
if(_rtbContent.InvokeRequired)
{
SaveNoteCallback d = new SaveNoteCallback(SaveNote);
this.Invoke(d, new object[] {path});
}
else
{
_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText);
}
}
I got another interesting solution and would like to post that.
public void SaveNote(string path)
{
if(_rtbContent.InvokeRequired)
{
_rtbContent.Invoke(new MethodInvoker(delegate{_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText}));
//Below is also same as above
//_rtbContent.Invoke(new MethodInvoker(()=>_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText)));
}
else
{
_rtbContent.SaveFile(path, RichTextBoxStreamType.RichText);
}
}
I think it is much clean solution. Hope it helps.
Essentially, I have a Do..While loop going through some lines from a text file. I want to process a line, return a value (worked or didn't), then move to the next line.
I have a function called ProcessTXT that accepts 2 strings. Source and Destination of new file.
Is there a way to set a ReturnedValue string = to the result and have the backgroundworker check to see if the variable changed? And if so, add this value to the list box?
private void TranslatePOD(string strSource, string strDest,)
{
TextWriter tw = new StreamWriter(strDest);
TextReader tr = new StreamReader(strSource);
do
{
//My Code doing stuff
//Need to send a result somehow now, but i have more work to do in this loop
//Then using tw.writeline() to write my results to my new file
} while (tr.ReadLine() != null);
}
EDIT: Current test code using Yield. My output is "TestingGround.Form1+d__0". Did i do something wrong?
namespace TestingGround
{
public partial class Form1 : Form
{
static IEnumerable<string> TestYield(string strSource)
{
TextReader tr = new StreamReader(strSource);
string strCurLine = System.String.Empty;
while ((strCurLine = tr.ReadLine()) != null)
{
yield return strCurLine;
}
}
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string MySource = System.String.Empty;
MySource = #"C:\PODTest\Export Script\Export\Shipment List.csv";
listBox1.Items.Add(TestYield(MySource));
}
}
Yield is typically used to return results iteratively, or streaming. There are plenty of examples online. There's one on SO for reading in a file.
It sounds like this is a good case for a producer/consumer queue. C# 4.0 introduced BlockingCollection, which is great for this. Create the blocking collection and ensure that both this process, and whatever needs to consume the results you are passing have access to it. This method can add items to the queue, and whatever is reading the results can use the Take method, which will block [wait] until there is at least one item to take out. The collection is specifically designed to work in multithreaded environments; all of the operations are logically atomic.
I have two methods in a C# business logic class. I need a flag mechanism so that one method can update the flag and the other method will react when the flag is updated. Below I will paste my situation, which is very simple:
// BusinessLogic.cs
bool photoResizingFinished = false;
public int SavePhoto() {
while (!photoResizingFinished) {
System.Threading.Thread.Sleep(100);
Trace.TraceInformation("PhotoResizingWorkerRole has not finnished yet.");
} }
public bool UpdateStatus(bool statusUpdate) {
photoResizingFinished = statusUpdate;
return true;
}
The two methods above live in the same class BusinessLogic.cs.
The only thing I need is to be able to have SavePhoto() react when
the bool photoResizingFinished is updated by UpdateStatus(bool statusUpdate)
You can use the class as a webservice and implement callback function that called when the ws finishes its work.
example code:
<script>
var timerID = setTimeout(CallWS, 1000)//call a js func which calls the WevService
function CallWS()
{
clearTimeout(timerID)//to stop the calling...
WSClassName.WSFuncName(param1,param2,....,callBackSuccess,callBackFailur)
///the param1,param2 are according to the parameter the function is expected to get.
}
function callBackSuccess(result,eventArgs)
{
//When the WS function finished successfuly
//**set flag to true.**
}
function callBackFailur(result,eventArgs)
{
//when error occured in the WS function
alert(result.get_message()).
}
</script>
Let me know if you need more help...
goodluck!
You could try using the Task class from .Net 4. It allows you to queue up tasks, so your SavePhoto() code would wait until the PhotoResizing() method finished.
Here's a nice article on the Task namespace if you want more details: http://www.codethinked.com/net-40-and-systemthreadingtasks
using System.Threading.Tasks;
public void SavePhoto(CancellationTokenSource taskCancellationTokenSource){
// preliminary code
// start resize
Task resizeTask = Task.Factory.StartNew( ResizePhoto, taskCancellationTokenSource ) ;
// queue up final save method
Task finalTask = resizeTask.ContinueWith(t => {
if (!t.IsFaulted && !t.IsCancelled){
FinishSaving();
}
});
// Wait for everything to finish
finalTask.Wait(taskCancellationTokenSource);
}
public void ResizePhoto(){
// code
}
public void FinishSaving(){
// code
}
I'd change the bool like this:
bool _photoResizingFinished=false;
bool photoResizingFinished
{
get{return _photoResizingFinished;}
set
{
if(value) SavePhoto();
_photoResizingFinished=value;
}
}
Or, you can make UpdatePhoto() call SavePhoto() after updating the bool. Might be a better solution.
Maybe I have found a solution to my problem using a Multithreaded Singleton
http://msdn.microsoft.com/en-us/library/ff650316.aspx
Here are some attempts of implementation:
http://forums.asp.net/t/1783765.aspx/2/10?How+to+have+two+methods+of+the+same+class+flag+to+eachother+
http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/abd53523-658b-442a-bac0-1c74c1d90a90
I don't understand the mecanics of this myself totally, but I hope it's ok.