I have been working to write a SQL installer for my application and haven't been given a lot of time to work on it therefore its a bit dirty. My UI thread collects values from the form, plugs them into a series of SQL scritps and then one by one kicks them of "asynchronously" using SMO. Here is a sample of the calling method on the UI thread:
private static bool BeginScriptExecution(Dictionary<string, string[]> scripts)
{
try
{
foreach (var script in scripts)
{
if (script.Key.Length > 0)
{
SqlConnection conn = new SqlConnection();
conn = ReplaceDatabaseName(GetConnectionString(), script.Value[0]);
if (TestSqlConnection())
{
if (ConfigurationManager.AppSettings["useSMO"] == "1")
{
if (!RunDatabaseCommandsSmo(conn, script.Key, script.Value[1]).Result)
{
throw new Exception("Script failed to run. Error in SMO functions.");
}
}
else
{
if (!RunDatabaseCommandsNonSmo(conn, script.Key, script.Value[1]))
{
throw new Exception("Script failed to run. Non-SMO related failure.");
}
}
}
else
{
throw new Exception("Connection not available. Script failed to run");
}
}
}
return true;
}
catch (Exception ex)
{
log.Error(ex.ToString());
return false;
}
}
Here is my async method to run the command using SMO:
public static async Task<bool> RunDatabaseCommandsSmo(SqlConnection connectionString, string scriptText, string scriptName)
{
Helper.UpdateProgressLabel(scriptName);
bool isSuccess = false;
try
{
ServerConnection srvCon = new ServerConnection(connectionString);
Server server = new Server(srvCon);
//script = scriptText;
if (scriptName.Contains("Creating Database")||scriptName.Contains("Building objects"))
{
try
{
isSuccess = await Task.Run(() => RunCommand(scriptText, server))
.ConfigureAwait(continueOnCapturedContext:false);
return isSuccess;
}
catch(Exception ex)
{
log.Error("Cannot create database");
log.Error(ex.StackTrace.ToString());
return false;
}
}
else
{
try
{
//server.ConnectionContext.ExecuteNonQuery(scriptText);
isSuccess = await Task.Run(() => RunTransaction(scriptText, server, srvCon))
.ConfigureAwait(continueOnCapturedContext: false);
return isSuccess;
}
catch (Exception ex)
{
log.Error(string.Format("Error writing transaction from script {0}. Installation halted - check inner exception.", scriptName));
log.Error(ex.ToString());
log.Error(ex.StackTrace.ToString());
return false;
}
}
}
catch (Exception ex)
{
log.Error(string.Format("Error writing transaction from script {0}. Installation halted - check inner exception.", scriptName));
log.Error(ex.StackTrace.ToString());
return false;
}
}
Here is the code running the transactions:
static bool RunCommand(string script, Server server)
{
try
{
server.ConnectionContext.ExecuteNonQuery(script);
return true;
}
catch(Exception ex)
{
log.Error(ex.ToString());
return false;
}
}
static bool RunTransaction(string script, Server server, ServerConnection srvCon)
{
try
{
srvCon.BeginTransaction();
server.ConnectionContext.ExecuteNonQuery(script);
srvCon.CommitTransaction();
return true;
}
catch (Exception ex)
{
srvCon.RollBackTransaction();
log.Error(ex.ToString());
return false;
}
}
Before I started moving towards async I was running all on the UI thread and the form would give me "Not Responding" until the script returned completed. Once I moved to this style of async the app is a bit more responsive and I no longer get not responding, but I am not sure of this method and whether or not it is correct use of async. Can someone let me know how I can alter my code to make this work correctly? There are 4 scripts that run and must run in specific order meaning script 2 cannot run until script 1 returns.
A good way to use asynchronous tasks is using a background worker,
take a look at the code example here:
Background Worker
If B.G. is the way you go, here is an example: How to: Implement a Form That Uses a Background Operation
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace BackgroundWorkerExample
{
public class FibonacciForm : System.Windows.Forms.Form
{
private int numberToCompute = 0;
private int highestPercentageReached = 0;
private System.Windows.Forms.NumericUpDown numericUpDown1;
private System.Windows.Forms.Button startAsyncButton;
private System.Windows.Forms.Button cancelAsyncButton;
private System.Windows.Forms.ProgressBar progressBar1;
private System.Windows.Forms.Label resultLabel;
private System.ComponentModel.BackgroundWorker backgroundWorker1;
public FibonacciForm()
{
InitializeComponent();
InitializeBackgroundWorker();
}
// Set up the BackgroundWorker object by
// attaching event handlers.
private void InitializeBackgroundWorker()
{
backgroundWorker1.DoWork +=
new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerCompleted +=
new RunWorkerCompletedEventHandler(
backgroundWorker1_RunWorkerCompleted);
backgroundWorker1.ProgressChanged +=
new ProgressChangedEventHandler(
backgroundWorker1_ProgressChanged);
}
private void startAsyncButton_Click(System.Object sender,
System.EventArgs e)
{
// Reset the text in the result label.
resultLabel.Text = String.Empty;
// Disable the UpDown control until
// the asynchronous operation is done.
this.numericUpDown1.Enabled = false;
// Disable the Start button until
// the asynchronous operation is done.
this.startAsyncButton.Enabled = false;
// Enable the Cancel button while
// the asynchronous operation runs.
this.cancelAsyncButton.Enabled = true;
// Get the value from the UpDown control.
numberToCompute = (int)numericUpDown1.Value;
// Reset the variable for percentage tracking.
highestPercentageReached = 0;
// Start the asynchronous operation.
backgroundWorker1.RunWorkerAsync(numberToCompute);
}
private void cancelAsyncButton_Click(System.Object sender,
System.EventArgs e)
{
// Cancel the asynchronous operation.
this.backgroundWorker1.CancelAsync();
// Disable the Cancel button.
cancelAsyncButton.Enabled = false;
}
// This event handler is where the actual,
// potentially time-consuming work is done.
private void backgroundWorker1_DoWork(object sender,
DoWorkEventArgs e)
{
// Get the BackgroundWorker that raised this event.
BackgroundWorker worker = sender as BackgroundWorker;
// Assign the result of the computation
// to the Result property of the DoWorkEventArgs
// object. This is will be available to the
// RunWorkerCompleted eventhandler.
e.Result = ComputeFibonacci((int)e.Argument, worker, e);
}
// This event handler deals with the results of the
// background operation.
private void backgroundWorker1_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
// First, handle the case where an exception was thrown.
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
else if (e.Cancelled)
{
// Next, handle the case where the user canceled
// the operation.
// Note that due to a race condition in
// the DoWork event handler, the Cancelled
// flag may not have been set, even though
// CancelAsync was called.
resultLabel.Text = "Canceled";
}
else
{
// Finally, handle the case where the operation
// succeeded.
resultLabel.Text = e.Result.ToString();
}
// Enable the UpDown control.
this.numericUpDown1.Enabled = true;
// Enable the Start button.
startAsyncButton.Enabled = true;
// Disable the Cancel button.
cancelAsyncButton.Enabled = false;
}
// This event handler updates the progress bar.
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.progressBar1.Value = e.ProgressPercentage;
}
// This is the method that does the actual work. For this
// example, it computes a Fibonacci number and
// reports progress as it does its work.
long ComputeFibonacci(int n, BackgroundWorker worker, DoWorkEventArgs e)
{
// The parameter n must be >= 0 and <= 91.
// Fib(n), with n > 91, overflows a long.
if ((n < 0) || (n > 91))
{
throw new ArgumentException(
"value must be >= 0 and <= 91", "n");
}
long result = 0;
// Abort the operation if the user has canceled.
// Note that a call to CancelAsync may have set
// CancellationPending to true just after the
// last invocation of this method exits, so this
// code will not have the opportunity to set the
// DoWorkEventArgs.Cancel flag to true. This means
// that RunWorkerCompletedEventArgs.Cancelled will
// not be set to true in your RunWorkerCompleted
// event handler. This is a race condition.
if (worker.CancellationPending)
{
e.Cancel = true;
}
else
{
if (n < 2)
{
result = 1;
}
else
{
result = ComputeFibonacci(n - 1, worker, e) +
ComputeFibonacci(n - 2, worker, e);
}
// Report progress as a percentage of the total task.
int percentComplete =
(int)((float)n / (float)numberToCompute * 100);
if (percentComplete > highestPercentageReached)
{
highestPercentageReached = percentComplete;
worker.ReportProgress(percentComplete);
}
}
return result;
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
this.startAsyncButton = new System.Windows.Forms.Button();
this.cancelAsyncButton = new System.Windows.Forms.Button();
this.resultLabel = new System.Windows.Forms.Label();
this.progressBar1 = new System.Windows.Forms.ProgressBar();
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
this.SuspendLayout();
//
// numericUpDown1
//
this.numericUpDown1.Location = new System.Drawing.Point(16, 16);
this.numericUpDown1.Maximum = new System.Decimal(new int[] {
91,
0,
0,
0});
this.numericUpDown1.Minimum = new System.Decimal(new int[] {
1,
0,
0,
0});
this.numericUpDown1.Name = "numericUpDown1";
this.numericUpDown1.Size = new System.Drawing.Size(80, 20);
this.numericUpDown1.TabIndex = 0;
this.numericUpDown1.Value = new System.Decimal(new int[] {
1,
0,
0,
0});
//
// startAsyncButton
//
this.startAsyncButton.Location = new System.Drawing.Point(16, 72);
this.startAsyncButton.Name = "startAsyncButton";
this.startAsyncButton.Size = new System.Drawing.Size(120, 23);
this.startAsyncButton.TabIndex = 1;
this.startAsyncButton.Text = "Start Async";
this.startAsyncButton.Click += new System.EventHandler(this.startAsyncButton_Click);
//
// cancelAsyncButton
//
this.cancelAsyncButton.Enabled = false;
this.cancelAsyncButton.Location = new System.Drawing.Point(153, 72);
this.cancelAsyncButton.Name = "cancelAsyncButton";
this.cancelAsyncButton.Size = new System.Drawing.Size(119, 23);
this.cancelAsyncButton.TabIndex = 2;
this.cancelAsyncButton.Text = "Cancel Async";
this.cancelAsyncButton.Click += new System.EventHandler(this.cancelAsyncButton_Click);
//
// resultLabel
//
this.resultLabel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
this.resultLabel.Location = new System.Drawing.Point(112, 16);
this.resultLabel.Name = "resultLabel";
this.resultLabel.Size = new System.Drawing.Size(160, 23);
this.resultLabel.TabIndex = 3;
this.resultLabel.Text = "(no result)";
this.resultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
//
// progressBar1
//
this.progressBar1.Location = new System.Drawing.Point(18, 48);
this.progressBar1.Name = "progressBar1";
this.progressBar1.Size = new System.Drawing.Size(256, 8);
this.progressBar1.Step = 2;
this.progressBar1.TabIndex = 4;
//
// backgroundWorker1
//
this.backgroundWorker1.WorkerReportsProgress = true;
this.backgroundWorker1.WorkerSupportsCancellation = true;
//
// FibonacciForm
//
this.ClientSize = new System.Drawing.Size(292, 118);
this.Controls.Add(this.progressBar1);
this.Controls.Add(this.resultLabel);
this.Controls.Add(this.cancelAsyncButton);
this.Controls.Add(this.startAsyncButton);
this.Controls.Add(this.numericUpDown1);
this.Name = "FibonacciForm";
this.Text = "Fibonacci Calculator";
((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
this.ResumeLayout(false);
}
#endregion
[STAThread]
static void Main()
{
Application.Run(new FibonacciForm());
}
}
}
I have background worker where I am getting some callback in a thread and I am updating the UI and the progress bar as the states change. Currently there are 3 states 1) Cartridgr Drawer Closed 2) Processing 3) Processed.
First Time when the application starts everything works fine. The Run Worker Completed fires after the Processed state and I am launching an other success window through an event.
But for the second when I rerun the workflow without closing the application, I get the success Window when the worker still says Processing. Why is that also the remaining time that I am updating behaves incorrectly. Please help. (Please see the DoWork event Thread th I guess thats the issue).
//This method is a RelayCommand thats called on some button click
private void StartCurrentRun(bool obj)
{
this.worker = new BackgroundWorker();
this.worker.WorkerReportsProgress = true;
this.worker.WorkerSupportsCancellation = true;
StartTimer();
PropertyCallBackChangedInstance.PropertyChanged -= PropertyCallBackChangedInstance_PropertyChanged;
WhenCancelledBlurVolumesGrid = false;
this.worker.DoWork += this.DoWork;
this.worker.ProgressChanged += this.ProgressChanged;
this.worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
IsLiveProgress = true;
this.worker.RunWorkerAsync();
}
private void DoWork(object sender, DoWorkEventArgs e)
{
int OriginalTimeRemaining = SelectedVolumeEstimatedTime();
int TotalPrecentagebasedOnNumberOfStates = 50;
int PercentProgress = 100 / TotalPrecentagebasedOnNumberOfStates;
CurrentCartridgeStatus status = CurrentCartridgeStatus.NotProcessed;
var instance = ConnectToInstrument.InstrumentConnectionInstance;
instance.InitalizeRun();
Thread th = new Thread(() =>
{
PropertyCallBackChangedInstance.PropertyChanged += PropertyCallBackChangedInstance_PropertyChanged;
});
th.Start();
Thread th2 = new Thread(() =>
{
while (PropertyCallBackChangedInstance.CurrentCartridgeStatusChanged != CurrentCartridgeStatus.Processed)
{
lock (_objectForThread2)
{
if (OriginalTimeRemaining > 0)
{
OriginalTimeRemaining -= 2;
}
var time = TimeSpan.FromSeconds(OriginalTimeRemaining);
EstimatedTimeRemaining = string.Format("{0:00}:{1:00}:{2:00}",
time.Hours,
time.Minutes,
time.Seconds);
OnPropertyChanged("EstimatedTimeRemaining");
}
Thread.Sleep(2000);
}
});
th2.Start();
int counter = 0;
for (int i = 0; i < PercentProgress; i++)
{
//Keep checking to see if the Run is cancelled
if (WhenCancelledBlurVolumesGrid) //That means the run is cancelled
{
if (worker.CancellationPending)
{
e.Cancel = true;
worker.CancelAsync();
}
}
for (int j = counter; j <= TotalPrecentagebasedOnNumberOfStates; j++)
{
worker.ReportProgress(Math.Min(j, 100));
if (status != CurrentCartridgeStatus.Processed)
{
Thread.Sleep(55);
}
}
counter = 50;
TotalPrecentagebasedOnNumberOfStates += 50;
}
th.Join();
th2.Join();
}
private void PropertyCallBackChangedInstance_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "CurrentCartridgeStatusChanged")
{
var value = sender as InstrumentCallBackProperties;
CurrentStatus = EnumExtensions.GetDescription(value.CurrentCartridgeStatusChanged);
}
}
private void ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.ProgressValue = e.ProgressPercentage;
}
private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
EstimatedTimeRemaining = "00:00:00";
stopWatch.Stop();
timer.Stop();
Messenger.Default.Send(new NotificationMessage("RunComplete"));
if (e.Cancelled)
{
SelectedVolume = string.Empty;
}
else
{
IsLiveProgress = false;
if (IsRunSuccessfullyComplete != null && !WhenCancelledBlurVolumesGrid) //This indicates that Success will only open when the run is complete
{
IsRunSuccessfullyComplete(NoErrors);//This event opens the success window from a different page
}
WhenCancelledBlurVolumesGrid = true;
}
//I have some Dispose method that i am trying to do after the first run.
public void Dispose()
{
if (this.worker != null)
{
this.ProgressValue = 0;
this.worker.CancelAsync();
this.worker.Dispose();
this.worker = null;
timer = null;
stopWatch = null;
TimeElapsed = string.Empty;
}
}
I'm making a memory game and i need to set a timer to reset de images if they don't match but it doesn't work to turn the pictures back to hidden:
//set images
if (clickedLabel != null)
{
var Index = Convert.ToInt32(clickedLabel.Tag);
clickedLabel.Image = icons[Index];
//Check first clicked
if (firstClicked == null)
{
firstClicked = clickedLabel;
return;
}
secondClicked = clickedLabel;
timer1.Start();
}
Method timer1_Tick:
//Timer
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Stop();
firstClicked = null;
secondClicked = null;
}
This might work :
class YourClass
{
System.Timers.Timer aTimer;
void YourMethod()
{
//code
if (clickedLabel != null)
{
var Index = Convert.ToInt32(clickedLabel.Tag);
clickedLabel.Image = icons[Index];
//Check first clicked
if (firstClicked == null)
{
firstClicked = clickedLabel;
return;
}
secondClicked = clickedLabel;
SetTimer();
}
private static void SetTimer ()
{
//System.Timers.Timer aTimer; at the beginning of your class
aTimer = new System.Timers.Timer (2000); //the time you want in milliseconds
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = false;
aTimer.Enabled = true;
}
}
The AutoReset set to false will make the Elapsed event trigger only once. Then, you do what you want in that event.
private static void OnTimedEvent (Object source, ElapsedEventArgs e)
{
firstClicked = null;
secondClicked = null;
}
You might want to use Stop and Dispose methods on aTimer when you don't need it anymore.
You also should be more specific when posting questions, to be sure to have the help you need :)
I check a condition on my form_load event whether the form window should be closed or not. If so, a timer with an interval of 3000 will be started and after the tick, the form should be closed. When I check my debugger, even though the condition returns true, the debugger jumps over my timer.Start() method and my timer is never ticked.
I have defined the timer in my class as System.Windows.Forms.Timer timer; and this is how I am initiating it:
timer = new System.Windows.Forms.Timer();
this.timer.Enabled = true;
this.timer.Interval = 3000;
this.timer.Tick += new System.EventHandler(this.timer_Tick_1);
The tick event:
private void timer_Tick_1(object sender, EventArgs e)
{
this.Close();
}
And the condition is as simple as:
if (closeWindow)
timer.Start();
And trust me, the closeWindow returns true.
P.s. Strangely enough, this timer used to work. I know I have it messed up somewhere perhaps. But I do not know where.
Update: the form_load event
private void FormMain_Load(object sender, EventArgs e)
{
metroLabelBuild.Text = args["name"] + " " + args["action"];
if (CheckArguments(args, 18))
{
try
{
campaignRecipientsFileLocation = args["recipientsfile"].Trim();
campaignName = args["name"].Trim();
campaignDescription = args["description"].Trim();
campaignAction = args["action"].Trim();
campaignOutputFormat = args["outputformat"].Trim();
campaignType = args["type"].Trim().ToLower();
campaignDelimiter = args["delimeter"].Trim();
campaignOutputPath = args["outputpath"].Trim();
campaignFileName = args["filename"].Trim();
campaignId = Convert.ToInt64(args["id"].Trim());
campaignFixedCost = Convert.ToInt32(args["fixedcost"]);
campaignVariableCost = Convert.ToInt32(args["variablecost"]);
campaignControlGroup = Convert.ToInt32(args["controlgroup"]);
campaignFtpId = Convert.ToInt64(args["ftpid"].Trim());
campaignHasSpyList = (args["hasspylist"].ToLower().Equals("true") || args["hasspylist"].Equals("1")) ? true : false;
closeWindow = (args["closewindow"].ToLower().Equals("true") || args["closewindow"].Equals("1")) ? true : false;
campaignShouldUploadToFTP = (args["shoulduploadtoftp"].ToLower().Equals("true") || args["shoulduploadtoftp"].Equals("1")) ? true : false;
}
catch
{
listBoxMessages.Items.Add("Error preparing the arguments.");
continueProcess = false;
this.Close();
}
finally
{
logger = new Logger(loggerEnabled, cs);
fh = new FileHelper(logger);
rh = new RecipientHelper(logger);
dbh = new DatabaseHelper(logger, cs);
if (continueProcess)
{
InsertCampaignRun("Running");
RunCampaign();
if (closeWindow)
timer.Start();
}
}
}
else
{
if (closeWindow)
timer.Start();
}
}
I'm making a little game in C#
When the score is 100, I want two labels to display for one second, then they need to be invisible again.
At the moment I have in Form1:
void startTimer(){
if (snakeScoreLabel.Text == "100"){
timerWIN.Start();
}
}
private void timerWIN_Tick(object sender, EventArgs e)
{
int timerTick = 1;
if (timerTick == 1)
{
lblWin1.Visible=true;
lblWin2.Visible=true;
}
else if (timerTick == 10)
{
lblWin1.Visible = false;
lblWin2.Visible = false;
timerWIN.Stop();
}
timerTick++;
}
The timer's interval is 1000ms.
Problem = labels aren't showing at all
Timers are pretty new to me, so I'm stuck here :/
Try this :
void startTimer()
{
if (snakeScoreLabel.Text == "100")
{
System.Timers.Timer timer = new System.Timers.Timer(1000) { Enabled = true };
timer.Elapsed += (sender, args) =>
{
lblWin1.Visible=true;
timer.Dispose();
};
}
}
Try multithreaded System.Threading.Timer :
public int TimerTick = 0;
private System.Threading.Timer _timer;
public void StartTimer()
{
label1.Visible = true;
label2.Visible = true;
_timer = new System.Threading.Timer(x =>
{
if (TimerTick == 10)
{
Invoke((Action) (() =>
{
label1.Visible = false;
label2.Visible = false;
}));
_timer.Dispose();
TimerTick = 0;
}
else
{
TimerTick++;
}
}, null, 0, 1000);
}