|
Another victim of metrosexualisation? I've since noticed a couple of others in the same boat.
Cheers,
Peter
Software rusts. Simon Stephenson, ca 1994. So does this signature. me, 2012
|
|
|
|
|
It appears that way!
There were a couple of BR tags under my name that I don't remember placing there.
Anyway, all fixed. Thanks!
|
|
|
|
|
I dont think that the GUI thread is blocked, because using TPL I parse all the files. Then show the result in the grid.
I am minimizing the application after all these operations are completed. That mean app is Idle when i minimize.
If i maximize the app immediately or like after 5. 10 minutes, then i am ok. But after 30-40 minutes i am having issue.
I also use DEV Express grid o show the result.
My small attempt...
|
|
|
|
|
I just told about file parsing, but this behavior may not be related to that. Below is another strange behavior i am seeing.
This is happening only sometimes, which may/may not related to our issue.
Say i have opened any popup window or some applications ( like MS word, IE) from my main form. When I close that popup window/app then the main form will be minimized or some other app will come front. So i had to click the app icon from task bar to bring it back
My small attempt...
|
|
|
|
|
Ditto dave's answer, your UI thread is probably blocked. To resolve this:
Add a BackgroundWorker and create a DoWork handler.
Move your parsing code into there.
Where your parsing code was, call RunWorkerAsync on the BackgroundWorker .
... now your parsing will be done on a background thread so your UI will remain active. You can use ReportProgress with a ProgressChanged handler to pass back info to the UI thread if needed.
|
|
|
|
|
Thanks Dude, instead of BackgroundWorker is use Task and continue with.
Is there any way to check, what went wrong when i got this situation again?
My small attempt...
|
|
|
|
|
Not that I know of, but a good rule for any application that has a UI is to perform potentially long running tasks on another thread so the UI doesn't freeze.
|
|
|
|
|
Thanks Dave, i will get back soon after resolving this issue
My small attempt...
|
|
|
|
|
Hi, so I have multiple textboxes on my c# winform and I am looking for a method to validate each box.
My current implementation works, however I am trying to find a way to expand on it and report which textboxes are not validating successfully.
So say return a string or array where i can search through and then set an errorprovider on them.
This is my validation method.(The method is void and not a bool because i want to return a variable with the failed textboxes)
public bool Successful { get; set; }
public string Information { get; set; }
public void ValidateText(List<object> textbox)
{
foreach (object obj in textbox)
{
if (obj == "")
{
Successful = false;
}
else
{
Successful = true;
}
}
}
and here is my main code
List<object> textbox = new List<object>();
textbox.Add(FirstNTxt.Text);
textbox.Add(LastNTxt.Text);
textbox.Add(CourseTxt.Text);
FormValidation validate = new FormValidation();
validate.ValidateText(textbox);
if(!validate.Successful)
{
MessageBox.Show("error");
}
else
{
}
Any assistance will be appreciated, thanks.
modified 11-Mar-21 21:01pm.
|
|
|
|
|
Your ValidateText will set the Successful to indicate if the last entry in the textbox list is valid or not. All the checking of the earlier entries is lost.
Try something like:
public void ValidateText(List<TextBox> textboxes)
{
Successful = true;
foreach (var tb in textboxes)
{
if (string.IsNullOrEmpty(tb.Text))
{
Successful = false;
}
}
}
and then
List<TextBox> textboxes = new List<TextBox>();
textboxes.Add(FirstNTxt);
textboxes.Add(LastNTxt);
textboxes.Add(CourseTxt);
FormValidation validate = new FormValidation();
validate.ValidateText(textboxes);
if(!validate.Successful)
{
MessageBox.Show("error");
}
else
{
}
Personally, I'd probably make a validation method that operates on one string at a time and then validate and set the errorprovider directly for each TextBox one at a time. (Despite what I showed above, I wouldn't pass the actual TextBox references around. The method should validate the string, possibly returning an error message. The caller (form) passes the .Text and reports the error appropriately.)
|
|
|
|
|
This code well search for all text box in your form and validated it, and it will be better If you Use Tag for Description of Textbox so the user know what he is missing, Plus you avoid typing in the MessageBox something like "No Name" , No Phone" , etc ...
More Over you can tell which TextBox in the form is needed to be validate by checking that Tag if it's Empty or not.
private void CheckTextBox()
{
TxtName.Tag = "First Name";
TxtPhone.Tag = "Phone Number";
foreach (Control control in this.Controls)
{
if (control.GetType().Equals(typeof(TextBox)))
{
if (ValidateText(control.Text))
{
MessageBox.Show(control.Tag.ToString());
MessageBox.Show(control.Name);
}
}
}
}
private bool ValidateText(string text)
{
return text.Equals(string.Empty);
}
P.S :
You can assign the Tag for TextBox by properties Windows during design time.
|
|
|
|
|
Two fantastic suggestions. Thank you so much. Both of these solve the issue I was facing.
Once again, Thanks!
modified 11-Mar-21 21:01pm.
|
|
|
|
|
Sorry, i just got around to trying both methods. For the first one,
public void ValidateText(List textboxes)
{
Successful = true;
foreach (var tb in textboxes)
{
if (string.IsNullOrEmpty(tb.Text))
{
Successful = false;
}
}
}
how do i go about outputting the actual control name that failed? all i can do is echo tb.text which ofc is empty. Any help would be great.
modified 11-Mar-21 21:01pm.
|
|
|
|
|
What would be a good way to monitor a .ini file?
What I want to do is when the file has changed, I need to read the file and find specific text and change it and save the file.
I've attempted the file system watcher with little luck. The problem is it is firing before the file is unlocked. I have also tried to put a method in there to check if the file was locked which basically opens the file and on exception returns true if locked otherwise false.
I have also tried a looping method like this:
private void WriteFile(string file, StringBuilder sb, string oldValue)
{
StreamWriter sw = null;
try
{
sw = new StreamWriter(file, false);
sw.Write(sb.ToString());
sw.Close();
EventLog.WriteEntry("QBiniMonitor", "Successfully removed LASTUSERNAME. Old Value: " + oldValue, EventLogEntryType.Information);
}
catch (IOException)
{
WriteFile(file, sb, oldValue);
}
finally
{
if (sw != null)
{
sw.Close();
sw.Dispose();
}
}
}
It still errored out after it changes the value a couple times in a row. It changes it a couple times but then ends up with a uncaught IOException somehow
|
|
|
|
|
You can use this method in a loop until the ini file closed.
protected virtual bool IsFileLocked(FileInfo file)
{
FileStream stream = null;
try
{
stream = file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None);
}
catch (IOException)
{
return true;
}
finally
{
if (stream != null)
stream.Close();
}
return false;
}
|
|
|
|
|
The OP could try this, but there's a race condition here. What happens if he calls this method, and it returns false, and then he opens the file but an external process has taken a lock on the file?
|
|
|
|
|
JD86 wrote: It changes it a couple times but then ends up with a uncaught IOException somehow
catch (IOException)
{
WriteFile(file, sb, oldValue);
}
You should log all exceptions; I'm betting that your WriteFile is causing the new exception, which would throw something "unhandled". So, wrap that in a try-construction too, or move it somewhere else.
I'd also recommend using a using block, as opposed to a try-finally with explicit dispose - it's a bit more readable.
Bastard Programmer from Hell
if you can't read my code, try converting it here[^]
|
|
|
|
|
I would be tempted to rewrite this method like this:
private static readonly object SyncLock = new object();
private void WriteFile(string file, StringBuilder sb, string oldValue)
{
try
{
using (StreamWriter sw = new StreamWriter(file, false))
{
sw.Write(sb.ToString());
}
EventLog.WriteEntry("QBiniMonitor", "Successfully removed LASTUSERNAME. Old Value: " + oldValue, EventLogEntryType.Information);
}
catch (IOException)
{
lock (SyncLock)
{
Monitor.Wait(SyncLock, 200);
}
WriteFile(file, sb, oldValue);
}
} The using statement removes the need to explicitly close the stream, and the lock/Monitor elements help to pause the next call to WriteFile for 200 milliseconds. Without this, you have a tight loop in there with execution of WriteFile happening immediately on failure.
|
|
|
|
|
Whoa there Slick! I see a possible StackOverflow waiting to happen if the file never gets unlocked.
|
|
|
|
|
Indeed, but I'm only working with the OPs original code - yes, if it were my code, I'd add in terminating conditions. As I don't know what the OPs ultimate use case is here, I'm loathe to suggest this - I've just had to assume that the lock has a finite limit.
|
|
|
|
|
Pete O'Hanlon wrote: I've just had to assume that the lock has a finite
limit.
True. I don't know any more about his requirements than you. I just wanted to point out that it's not the ultimate solution for anyone else just scrounging for code.
Pete O'Hanlon wrote: I'm loathe to suggest this
Kinda makes you want to take a long shower, doesn't it?
|
|
|
|
|
Use the FileSystemWatcher, when it notifies you of a change put an entry on a queue with a retrieval time of 1 second (or 200ms or whatever is appropriate in the future), and have another thread which pulls things off that queue at the right time and actions them. In this case the action is 'read file, find text, replace, write file'. If it fails, re-queue it.
|
|
|
|
|
Based on the description, I believe this is what the OP has said he's done (all except for the pause bit).
|
|
|
|
|
Sorry for the delay responses! Just had a baby girl
Anyways let me explain. I'm setting up a multi-tenant quickbooks environment. The problem is as we probably all know is it wasn't really designed for multi-tenancy. Now everything works fine with what I have except the username is populated on a program level.
So in the ProgramData directory (All Users) there is a qbw.ini file that contains LASTUSERNAME=. Each time a user launches quickbooks it reads this information and prepopulated the username field for the company database login.
I don't want people seeing other peoples logins. Most just use Admin which isn't a big deal but some use their company name. So I don't want another company seeing that.
So my idea is to monitor that file for updates using a file system watcher and changing that value in the INI file to blank. So basically changing something like this: "LASTUSERNAME=Admin" to this: "LASTUSERNAME="
Quickbooks does not place a permanent lock on this file. So we don't have to worry about quickbooks locking it for a long period of time.
I'm trying suggestions as we speak. I'm adding an error count to stop the service if an exception happens so many times within a specific time period. Hopefully this will stop an overflow exception like you were talking about. I can make something to restart the service ever so often.
Not the best plan but so far thats what I got!
|
|
|
|
|
Alright so here is what I ended up with. It seems to work... catches the IO exceptions and continues running. So far it is working good enough for me
using System;
using System.Diagnostics;
using System.IO;
using System.ServiceProcess;
using System.Text;
using System.Threading;
namespace QBiniMonitor
{
public partial class QBMonitor : ServiceBase
{
FileSystemWatcher watcher2012;
FileSystemWatcher watcher2011;
string QB2012 = Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%") + @"\Intuit\QuickBooks 2012\";
string QB2011 = Environment.ExpandEnvironmentVariables("%ALLUSERSPROFILE%") + @"\Intuit\QuickBooks 2011\";
enum Version
{
QB2011,
QB2012
}
public QBMonitor()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
StartNewWatcher(Version.QB2011);
StartNewWatcher(Version.QB2012);
}
private void StartNewWatcher(Version watcherVersion)
{
if (watcherVersion == Version.QB2011)
{
watcher2011 = new FileSystemWatcher();
watcher2011.Path = QB2011;
watcher2011.Filter = "qbw.ini";
watcher2011.NotifyFilter = NotifyFilters.LastWrite;
watcher2011.Changed += new FileSystemEventHandler(watcher_Changed);
StartStopWatcher(Version.QB2011, true);
}
else if (watcherVersion == Version.QB2012)
{
watcher2012 = new FileSystemWatcher();
watcher2012.Path = QB2012;
watcher2012.Filter = "qbw.ini";
watcher2012.NotifyFilter = NotifyFilters.LastWrite;
watcher2012.Changed += new FileSystemEventHandler(watcher_Changed);
StartStopWatcher(Version.QB2012, true);
}
}
private void watcher_Changed(object sender, FileSystemEventArgs e)
{
FileSystemWatcher watcher = sender as FileSystemWatcher;
if (watcher.Path == QB2012)
StartStopWatcher(Version.QB2012, false);
else if (watcher.Path == QB2011)
StartStopWatcher(Version.QB2011, false);
bool saveFile = false;
string oldValue = string.Empty;
StringBuilder sb = new StringBuilder();
try
{
using (FileStream fs = new FileStream(e.FullPath, FileMode.Open, FileAccess.Read))
{
using (StreamReader sr = new StreamReader(fs))
{
while (sr.Peek() >= 0)
{
string currentLine = sr.ReadLine();
if (currentLine.StartsWith("LASTUSERNAME="))
{
if (!currentLine.Equals("LASTUSERNAME=Admin"))
{
sb.AppendLine("LASTUSERNAME=Admin");
oldValue = currentLine;
saveFile = true;
}
else
sb.AppendLine(currentLine);
}
else
sb.AppendLine(currentLine);
}
}
}
}
catch (Exception ex)
{
EventLog.WriteEntry("QBiniMonitor", "watcher_Changed::: " + ex.ToString(), EventLogEntryType.Error);
}
if (saveFile)
{
if (watcher.Path == QB2012)
WriteFile(Version.QB2012, e.FullPath, sb, oldValue, 1);
else if (watcher.Path == QB2011)
WriteFile(Version.QB2011, e.FullPath, sb, oldValue, 1);
}
else
{
if (watcher.Path == QB2012)
StartStopWatcher(Version.QB2012, true);
else if (watcher.Path == QB2011)
StartStopWatcher(Version.QB2011, true);
}
}
private static readonly object SyncLock = new object();
private void WriteFile(Version watcherVersion, string file, StringBuilder sb, string oldValue, int retryCount)
{
if (retryCount < 5)
{
try
{
using (StreamWriter sw = new StreamWriter(file, false))
{
sw.Write(sb.ToString());
}
EventLog.WriteEntry("QBiniMonitor", "Version: " + watcherVersion.ToString() + ". The value for the last username was cleared. The previous value was: " + oldValue, EventLogEntryType.Information);
StartStopWatcher(watcherVersion, true);
}
catch (IOException)
{
lock (SyncLock)
{
EventLog.WriteEntry("QBiniMonitor", "Version: " + watcherVersion.ToString() + ". File was locked. Waiting 2 seconds and trying again. Retry number: " + retryCount);
Monitor.Wait(SyncLock, 2000);
}
retryCount = retryCount + 1;
WriteFile(watcherVersion, file, sb, oldValue, retryCount);
}
}
else
{
EventLog.WriteEntry("QBiniMonitor", "WriteFile::: " + "Retry limit of 5 was reached while trying to change the data in the file. (Because the file was locked)", EventLogEntryType.Warning);
StartStopWatcher(watcherVersion, true);
}
}
private void StartStopWatcher(Version watcherVersion, bool start)
{
try
{
switch (watcherVersion)
{
case Version.QB2011:
if (start)
{
watcher2011.EnableRaisingEvents = true;
}
else
{
watcher2011.EnableRaisingEvents = false;
}
break;
case Version.QB2012:
if (start)
{
watcher2012.EnableRaisingEvents = true;
}
else
{
watcher2012.EnableRaisingEvents = false;
}
break;
default:
break;
}
}
catch (IOException ex)
{
EventLog.WriteEntry("QBiniMonitor", "StartStopWatcher::: " + ex.ToString(), EventLogEntryType.Error);
Stop();
}
catch (Exception ex)
{
EventLog.WriteEntry("QBiniMonitor", "StartStopWatcher::: " + ex.ToString(), EventLogEntryType.Error);
Stop();
}
}
protected override void OnStop()
{
if (watcher2011 != null)
{
watcher2011.EnableRaisingEvents = false;
watcher2011.Dispose();
}
if (watcher2012 != null)
{
watcher2012.EnableRaisingEvents = false;
watcher2012.Dispose();
}
}
}
}
|
|
|
|
|