ontextchanged async sql stored proc call - c#

I have a winform application and on the main form I placed a textbox.
What I want is that on the OnTextChanged event I need to query sql (stored proc) table in order to bring a list of matches with the character typed. For example if I type letter A then automaticly I should go and search in the database for names starting with letter "A", if I then type letter "L" then I should go and search for names starting with "AL" and so on.
The thing is that If I the user type fast then It should cancel any async process that is in progress and keep only the task for the last letter typed.
Any clue on how to achieve these?

The thing is that If I the user type fast then It should cancel any async process
It shouldn't need to cancel anything - the trick is not to start anything until you think the user has stopped typing.
I wrote something a bit similar, whereby when the user typed I had a thread start a new method, the method waited for a (configurable) time before executing. Another keystroke would call the method again and reset the wait period - effectively if someone continued to type the task wouldn't execute; as soon as they stopped it would (after a 200 ms pause for example).
I would implement something similar if I were you, as it avoids going to SQL when you don't have to
updated - by way of a simple example, a new project with a new form and default text box should allow the following code to function for your needs (as a very simple starting point)
public partial class Form1 : Form
{
private bool _waiting;
private bool _keyPressed;
private const int TypingDelay = 220; // ms used for delay between keystrokes to initiate search
public Form1()
{
InitializeComponent();
}
private void WaitWhileUserTyping()
{
var keepWaiting = true;
while (keepWaiting)
{
_keyPressed = false;
Thread.Sleep(TypingDelay);
keepWaiting = _keyPressed;
}
Invoke((MethodInvoker)(ExecuteSearch));
_waiting = false;
}
private void ExecuteSearch()
{
Thread.Sleep(200); // do lookup
// show search results...
MessageBox.Show("Search complete");
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (_waiting)
{
_keyPressed = true;
return;
}
_waiting = true;
// kick off a thread to do the search if nothing happens after x ms
ThreadPool.QueueUserWorkItem(_ => WaitWhileUserTyping());
}
}

Related

Restarting a method

I am making a C# aplication. I have got one main process for verifying data from a database. A timer checks every 100 ticks if I have user input. After I get user input my main process continues (it waits for userinput at the start). After verifying and doing multiple things the method is done. The thing is, I would like it to go to the beginning again waiting for the next bit of input.
I was thinking of calling the method again at every possible end of the process. I have a feeling that this will create a resource heavy program though (not the worst thing, but better no bad habits than a few right?).
Example:
bool cont = false;
public void process()
{
while (cont == false) {;}
//Various sorting criteria that all end up with cont = false; process(), the userinput has been processed.
}
timer1 tick event
{
if (userinput)
cont = true;
}
As you don't saw how you will get the user input, i don't implemented this one. But the main logic to your question is :
class MainClass
{
public static void Main()
{
MyRecursiveFunction();
AfterUserInput();
}
public static void MyRecursiveFunction()
{
if (userinput)
{ return; }
// Waits 100 ticks to check again
Thread.Sleep(new TimeSpan(100));
MyRecursiveFunction();
}
public static void AfterUserInput()
{
// All that you need to do after the user input
}
}

C# Trouble Using Safe Thead or Background Worker

Fairly frustrating since this seems to be well documented and the fact that I accomplished this before, but can't duplicate the same success. Sorry, I'll try to relate it all clearly.
Visual Studio, C# Form, One Main Form has text fields, among other widgets.
At one point we have the concept that we are "running" and therefore gathering data.
For the moment, I started a one second timer so that I can update simulated data into some fields. Eventually that one second timer will take the more rapid data and update it only once per second to the screen, that's the request for the application right now we update at the rate we receive which is a little over 70 Hz, they don't want it that way. In addition some other statistics will be computed and those should be the field updates. Therefore being simple I'm trying to just generate random data and update those fields at the 1 Hz rate. And then expand from that point.
Definition and management of the timer: (this is all within the same class MainScreen)
System.Timers.Timer oneSecondTimer;
public UInt32 run_time = 0;
public int motion = 5;
private void InitializeTimers()
{
this.oneSecondTimer = new System.Timers.Timer(1000);
this.oneSecondTimer.Elapsed += new System.Timers.ElapsedEventHandler(oneSecondTimer_elapsed);
}
public void start_one_second_timer()
{
run_time = 0;
oneSecondTimer.Enabled = true;
}
public void stop_one_second_timer()
{
oneSecondTimer.Enabled = false;
run_time = 0;
}
Random mot = new Random();
private void oneSecondTimer_elapsed(object source, System.Timers.ElapsedEventArgs e)
{
run_time++;
motion = mot.Next(1, 10);
this.oneSecondThread = new Thread(new ThreadStart(this.UpdateTextFields));
this.oneSecondThread.Start();
}
private void UpdateTextFields()
{
this.motionDisplay.Text = this.motion.ToString();
}
motionDisplay is just a textbox in my main form. I get the Invalid Operation Exception pointing me towards the help on how to make Thread-Safe calls. I also tried backgroundworker and end up with the same result. The details are that motionDisplay is accessed from a thread other than the thread it was created on.
So looking for some suggestions as to where my mistakes are.
Best Regards. I continue to iterate on this and will update if I find a solution.
Use a System.Forms.Timer rather than a System.Timers.Timer. It will fire it's elapsed event in the UI thread.
Don't create a new thread to update the UI; just do the update in the elapsed event handler.
Try this
private void UpdateTextFields()
{
this.BeginInvoke(new EventHandler((s,e)=>{
this.motionDisplay.Text = this.motion.ToString();
}));
}
This will properly marshall a call back to the main thread.
The thing with WinForm development is that all the controls are not thread safe. Even getting a property such as .Text from another thread can cause these type of errors to happen. To make it even more frustrating is that sometimes it will work at runtime and you won't get an exception, other times you will.
This is how I do it:
private delegate void UpdateMotionDisplayCallback(string text);
private void UpdateMotionDisplay(string text) {
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.motionDisplay.InvokeRequired) {
UpdateMotionDisplayCallback d = new UpdateMotionDisplayCallback(UpdateMotionDisplay);
this.Invoke(d, new object[] { text });
} else {
this.motionDisplay.Text = text;
}
}
When you want to update the text in motionDisplay just call:
UpdateMotionDisplay(this.motion.ToString())

C# BackgroundWorker

I have a button that on click event I get some information from the network.
When I get information I parse it and add items to ListBox. All is fine, but when I do a fast double-click on button, it seems that two background workers are running and after finishing all work, items in the list are dublicated.
I want to do so that if you click button and the proccess of getting information is in work, this thread is stopping and only after first work is completed the second one is beginning.
Yes, I know about AutoResetEvent, but when I used it it helped me only one time and never more. I can't implement this situation and hope that you will help me!
Now I even try to make easier but no success :( : I added a flag field(RefreshDialogs)(default false), when the user clicks on button, if flag is true(it means that work is doing), nothing is doing, but when flag field is set to false, all is fine and we start a new proccess.
When Backgroundwork completes, I change field flag to false(it means that user can run a new proccess).
private void Message_Refresh_Click(object sender, EventArgs e)
{
if (!RefreshDialogs)
{
RefreshDialogs = true;
if (threadBackgroundDialogs.WorkerSupportsCancellation)
{
threadBackgroundDialogs.CancelAsync();
}
if (!threadBackgroundDialogs.IsBusy)
{
downloadedDialogs = 0;
threadBackgroundDialogs = new BackgroundWorker();
threadBackgroundDialogs.WorkerSupportsCancellation = true;
threadBackgroundDialogs.DoWork += LoadDialogs;
threadBackgroundDialogs.RunWorkerCompleted += ProcessCompleted;
threadBackgroundDialogs.RunWorkerAsync();
}
}
}
void ProcessCompleted(object sender, RunWorkerCompletedEventArgs e)
{
RefreshDialogs = false;
}
So you want to keep the second process running while the first works, but they shouldn't disturb each other? And after the first one finishes the second one continues?
Crude way: While loop:
if (!RefreshDialogs)
{
RefreshDialogs = true;
this becomes:
while(RefreshDialogs)
{
}
RefreshDialogs = true;
After you set it false the second process wwill jump out of the while. (Note this is extremly inefficent since both processes will be running all the time, i'm pretty sure the second one will block the first one, but with multitasking now it shouldn't, if it block use a Dispatcher.Thread)
Elegant way: Use A Semaphore
http://msdn.microsoft.com/de-de/library/system.threading.semaphore%28v=vs.80%29.aspx
If you find it impossible to have both processes running at the same time, or want another way:
Add an Array/List/int and when the second process notices there is the first process running, like with your bool, increase your Added variable, and at the end of the process, restart the new process and decrese the variable:
int number;
if (!RefreshDialogs)
{
RefreshDialogs = true;
your code;
if(number > 0)
{
number--;
restart process
}
}
else
{
number++;
}
I have to admit, i like my last proposal the most, since its highly efficent.
Make your thread blocking. That is easy;
lock(someSharedGlobalObject)
{
Do Work, Exit early if cancelled
}
This way other threads will wait until the first thread releases the lock. They will never execute simultaneously and silently wait until they can continue.
As for other options; why not disable the button when clicked and re-enable it when the backgroundworker completes. Only problem is this does not allow for cancelling the current thread. The user has to wait for it to finish. It does make any concurrency go away very easily.
How about this approach?
Create a request queue or counter which will be incremented on every button click. Every time that count is > 0. Start the background worker. When the information comes, decrement the count and check for 0. If its still > 0 restart the worker. In that your request handler becomes sequential.
In this approach you may face the problem of continuous reference of the count by two threads, for that you may use a lock unlock condition.
I hav followed this approach for my app and it works well, hope it does the same for you.
I'm not an Windows Phone expert, but as I see it has support for TPL, so following code would read nicely:
private object syncRoot =new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
latestTask = Task.Factory.StartNew(action);
else
latestTask = latestTask.ContinueWith(tsk => action());
}
}
Use can use semaphores
class TheClass
{
static SemaphoreSlim _sem = new SemaphoreSlim (3);
static void Main()
{
for (int i = 1; i <= 5; i++)
new Thread (Enter).Start (i);
}
static void Enter (object name)
{
Console.WriteLine (name + " wants to enter");
_sem.Wait();
Console.WriteLine (name + " has entered!");
Thread.Sleep (1000 * (int) name );
Console.WriteLine (name + " is leaving");
_sem.Release(); }
}
}
I found the solution and thanks to #Giedrius. Flag RefreshingDialogs is set to true only when proccess is at the end, when I added items to Listbox. The reason why I'am using this flag is that state of process changes to complete when the asynchronous operation of getting content from network(HttpWebRequest, method BeginGetRequestStream) begins, but after network operaion is complete I need to make UI operations and not only them(parse content and add it to Listbox)My solution is:
private object syncRoot = new object();
private Task latestTask;
public void EnqueueAction(System.Action action)
{
lock (syncRoot)
{
if (latestTask == null)
{
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
else if(latestTask.IsCompleted && !RefreshingDialogs)
{
RefreshingDialogs = true;
downloadedDialogs = 0;
latestTask = Task.Factory.StartNew(action);
}
}
}
private void Message_Refresh_Click(object sender, EventArgs e)
{
Action ac = new Action(LoadDialogs2);
EnqueueAction(ac);
}

c# button click queueing

I have a button click event handler with a switch case in it that controls multiple buttons in one event handler.
I need to use a queue because while one button is clicked and doing some processing, second button click won't interfere with the first button click, but added to the queue. I don't want to use .enabled=false; because it'll discard the second click completely, and I'm currently editing someone's software at work so I don't want to break things that I don't know, so what are you suggesting?
The best idea, I think, is to create a producer/consumer queue.
Another question is explaining this technique.
Basically, the idea is to have a worker thread that will consume a queue to get the job to do, while other thread produce job by queuing operation in the queue.
I did succeed this with System.Collections.Queue
The code is :
private Queue<Button> Button_Queue = new Queue<Button>();
private bool isProcessing = false;
private void Button_Click((object sender, EventArgs e){
if(isProcessing){
Button_Queue.Enqueue(this);
}
else
{
isProcessing = true;
// code here
isProcessing = false;
while(Button_Queue.Count > 0){
Button_Queue.Dequeue().PerformClick();
}
}
of course mine is slightly different from this because I need to pass some variables and my click method is modified for this.
Dirty, but simple solution.
public partial class DataRefresh : Form //DataRefresh is just "some form"
{
...
...
public DateTime ClickTime; //Time when click is processed by system
public DateTime LastExecutionRunTime = DateTime.MinValue; //Time when the all the click code finish
private void buttonDataRefresh_Click(object sender, EventArgs e)
{
ClickTime = DateTime.Now;
if (ClickTime.Subtract(LastExecutionRunTime).TotalSeconds < 5 )
{
//It will keep returning - hopefully until all events in que are satisfied
return;
}
//Long running code
//Importing whole table from remote DB
...
...
//End of the Long running code
LastExecutionRunTime = DateTime.Now;
}
}

breaking out of my infinite loop

I have two buttons one for start and one for stop in my UI form,and i have one infinite loop that executes some function in my class name programs in a method.The start button is clicked by the user it invokes this method to execute the infinite loop and i need to break this infinite loop when the user clicks the stop button,after that my compiler will break out of this infinite loop and enters to the code inside the button stop click.
I am trying to use the Application.DoEvents() method,this is working well if my infinite loop code is inside of the start button click,but if my infinite loop code is in the new class which is created by me i.e programs,how can use the Application.DoEvents() method to break out of this infinite loop.
Example:
namespace inFiniteLoopTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool stopBtnClk = false;
bool startBtnClk = false;
private void StartBtn_Click(object sender, EventArgs e)
{
stopBtnClk=false;
startBtnClk = true;
while(true)
{
//some code to be executed
Application.DoEvents();
if (stopBtnClk == true)
{
break;
}
}
}
private void StopBtn_Click(object sender, EventArgs e)
{
stopBtnClk = true;
if (startBtnClk == true)
{
//Application.Exit();
MessageBox.Show("success");
}
}
this is working well.
But
public class programs
{
public static void infiniteLoop(bool stopBtnClick)
{
while(true)
{
//some code to be executed
Application.DoEvents();
if (stopBtnClk == true)
{
break;
}
}
}
}
//and my UI code to call this class is
namespace inFiniteLoopTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
bool stopBtnClk = false;
bool startBtnClk = false;
private void StartBtn_Click(object sender, EventArgs e)
{
stopBtnClk=false;
startBtnClk = true;
programs.infiniteLoop(stopBtnClk);
}
private void StopBtn_Click(object sender, EventArgs e)
{
stopBtnClk = true;
if (startBtnClk == true)
{
//Application.Exit();
MessageBox.Show("success");
}
}
}
but this is not working .
Even if the compiler displays the message "success" when the stop button is clicked, but the debugger still said running in my form.
I hope my question is clear.
And i am kindly requesting you to answer my question as soon as possible and get rid of this problem!
I openly accept your answer if you come especially with a thread.
sorry i am a beginner for C#, but i need to continue on that.
Thank you!!
Don't block the GUI thread. The fact that you have to use Application.DoEvents() to update the GUI is an indicator for bad design. Do the work in a separate worker thread.
BackgroundWorker is predestinated for such a task.
Change signature of your infiniteLoop method like this:
public static void infiniteLoop(ref bool stopBtnClick)
...
The code you have provided is really difficult to read but as far as I can see when you create your infinite loop do:while(looping) // do stuff
Then when you press the Stop button set the bool variable looping to false and it will break out of the loop and show the message.
In the second code snippet, the infinite loop is started in a subroutine that accepts a boolean value as a parameter. How does that subroutine ever get a second chance to take a look at that boolean? It only "sees" the value once, and it's false at that time. It's a scoping question.
Why instead of an infinite loop you use a start stop condition determined by the buttons?
I thinking you can have a variable, just call it
bool stop_loop = false
and your loop
while(!stop_loop){ //CODE HERE }
Now when you click the first button (Start) you call the method (wherever it is) to start the loop. The loop is going to seem endless until you click the button stop and the value of stop_loop become in True.
HTH

Categories