i'm try to develope a list of result by a dynamic search in a text box.
Now i update the record when:
SearchBox.TextChanged += new EventHandler(SearchBox_TextChanged);`
But i have to wait every char that i write for the complete result of the list.
so if i search for example "com" the result is not words that contains "com" but only "c".
For have the result of "com" i need to write:
"c" -> Wait to complete search
"o" -> Wait to complete search
"m" -> Wait to complete search
How can i do for wait some time that the user write the word and then search?
Thanks.
You are not aware what user want to insert in text box, so may be is Cat, Contact, Com, Computer,... So you should restrict the search list by each keyword from user, also you can set a policy for example just search when the input length is at least 3.
Edit: The other way is to use Lazy pattern, means keep the last time of text changed, then in another thread (like timer) check if there is more than 2 second between last user change to current time, update your search: (timer interval is 2 second).
private DateTime lastChange = DateTime.Now;
private bool textChanged = false;
object lockObject = new object();
private void textChanged(object sender, EventArg e)
{
lock(lockObject)
{
lastChange = DateTime.Now;
textChanged = true;
}
}
private void timer1_Tick(object sender, EventArgs ะต)
{
lock(lockObject)
{
if (textChanged && lastChange > DateTime.Now.AddSeconds(-2)) // wait 2 second for changes
{
UpdateList(); // or the method for searching.
textChanged = false;
lastChange = DateTime.Now;
}
}
}
the easiest way is to add into the event handler a condition like a minimum length
private void SearchBox_TextChanged(Event e,...){
if(e.text.Length > 3)
search(e.text);
}
Use a Timer. On every TextChanged event,
start that timer if not running,
restart (stop & start) if already running,
On Timer's Tick event, write your code to update Search Results and stop timer.
This will give your users some time to write complete search key-words.
Usually Timer Interval can be around 1 Second.
You can create a Timer when your application starts, and then on every keystroke simply reset and re-start the timer.
When the user stops typing, the timer will execute and perform the search.
You can use timer with an Interval of some like 2 seconds and implement search within timer's Tick event. Enable timer within TextChanged event and once search completed then disable timer within Tick event.
Related
In my WPF application, I have an event handler that gets called on the MouseEnter event of my UI element:
myUiElement.MouseEnter += myEventHandler
I would like to throttle myEventHandler so it doesn't get called more than once every second. How can I do this? Is Rx the best approach just for this? I'm using .NET 4.0 if it makes a difference.
Also, I need to make sure that the MouseLeave event always gets called before the next MouseEnter event; do I need to manage this on my own? Or is the framework already designed so that MouseLeave events will always be called before the next MouseEnter event? What if I have asynchronous code in these event handlers?
Using Rx, you want to use the Sample method or Throttle.
Something like this should work (untested):
Observable
.FromEventPattern<TextChangedEventArgs>(myUiElement, "MouseEnter")
.Sample(TimeSpan.FromSeconds(1))
.Subscribe(x => ... Do Stuff Here ...);
The difference between Sample and Throttle is that Sample will take a value every 1 second no matter when the last value was taken, whereas Throttle will take a value and then wait another 1 second before taking another.
It probably depends on what you are shooting for...
You could use reactive extensions, but you could accomplish this just as easily with a timer.
Set a flag along with a Timer. When the timer tick event fires, set the flag to false, disable the timer, and run the code for your event. Then, in your control event handlers, have the handler code skipped if the flag is set.
bool flag;
DispatcherTimer timer;
public constructor()
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += (s,e) => {
flag = false;
timer.Stop()
DoThrottledEvent();
}
}
void mouse_enter(object sender, MouseEventArgs args)
{
if(!flag)
{
flag = true;
timer.Start();
}
}
void DoThrottledEvent()
{
//code for event here
}
Reactive extensions introduces an extra dependency, but they are a bit of fun. If you are interested, go for it!
Another approach would be to use a private field to keep track of the "time" when the last mouse event occurred, and only continue processing if that time was more than one second ago.
DateTime _lastMouseEventTime = DateTime.UtcNow;
void OnMouseEnter(object sender, MouseEventArgs e)
{
DateTime now = DateTime.UtcNow;
if (now.Subtract(_lastMouseEventTime).TotalSeconds >= 1)
{
// do stuff...
}
_lastMouseEventTime = now;
}
This ensures that "stuff" gets done at least one second apart, which is what I think you were asking for.
I have a textbox and a listbox in my app. Also i have a text file with many players. What I want is whenever the user enters some text, look in the players file and add the matching players to the matching list which is the data source for the listbox. The problem is that it seems to be very slow and UI freezes a short time but it's quite annoying.
This is the code i have:
private void tb_playername_TextChanged(object sender, EventArgs e)
{
//This method is used to show user the options he can choose with the text he has entered
List<string> matching_players = new List<string>();
foreach (var item in all_players)
{
string player = item.f_name + " " + item.l_name;
if ((player.IndexOf(tb_playername.Text, StringComparison.OrdinalIgnoreCase) >= 0))
{
matching_players.Add("(" + item.rating + ") " + item.f_name + " " + item.l_name);
}
}
if (tb_playername.Text.Length >= 4)
{
matching_players.Sort();
matching_players.Reverse()
listbox_matchingplayers.DataSource = matching_players;
}
}
The problem is that you are doing a relatively time consuming task in the event handler. Event handlers operate on the same thread which takes care of rendering your application and handle any other visual aspects of it, so if this thread is busy, it will not be in a position to react to user input immediately, hence freezing.
The standard approach to this problem is to offload the time consuming tasks to a Background Worker. The background worker will operate in a new thread thus allowing the main thread to continue handling UI events. This example should hopefully put you on the right track when it comes to using a background worker.
EDIT: As per your question, what you could do would be to start searching only when a particular amount of characters is entered, for instance 3, this would reduce the amount of time the background worker runs. If the user keeps on typing, you could stop the current background worker if running and launch a new one.
The background worker will fire an event when finished. You could use the RunWorkerCompletedEventArgs.Result to then extract the returned list act upon it.
private async void tb_playername_TextChanged(object sender, EventArgs e)
{
var text = (sender as TextBox).Text;
// Check length of the text
if (string.IsNullOrEmpty(text) || text.Length <= 3)
return;
// Check timer to not process if user still typing, by measuring the key stoke time
...
// Filtering
List<string> matching_players = await PlayerFilter(text);
// Minimize listbox layout time
listbox_matchingplayers.SuspendLayout();
listbox_matchingplayers.DataSource = matching_players;
listbox_matchingplayers.ResumeLayout();
}
//Time consuming method
private async Task<List<string>> PlayerFilter(string text)
{
//This method is used to show user the options he can choose with the text he has entered
return matching_players;
}
For details of the user typing check wait for user to finish typing in a Text Box
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;
}
}
The following code hides a form for 10 seconds. Nothing too crazy.
Each time the button is pressed, it creates a new timer object that doesn't stop and just keeps going. My intuition tells me that if you end up pressing this button many times, you'll have a bunch of timers that are running when only one is necessary (or is my assumption incorrect?). Also, if I do need to stop and dispose this timer, would I just send it as an argument in RevealForm or have the timer be a class level variable and just stop/reset it each time?
private void ButtonHide_Click(object sender, EventArgs e) {
this.Visible = false;
System.Timers.Timer t = new System.Timers.Timer();
t.Elapsed += new ElapsedEventHandler(RevealForm);
t.Interval = 10000;
t.AutoReset = false;
t.Start();
}
private void RevealForm(object source, ElapsedEventArgs e) {
InvokeReveal();
}
private void InvokeReveal() {
if (InvokeRequired) {
Invoke(new Action(InvokeReveal));
}
else {
this.Visible = true;
}
}
Thanks much!
Create the timer in the class then call t.start() on each click.
No need to destroy/cleanup/etc. Just recycle the one you have.
Your assumption is correct - testing would have asserted such for you.
You could either:
A) Disable the timer after each execution (per-interval) and enable on click, or,
B) Stop and destroy the timer and create a new one with each click.
Either option will require a little refactoring of your existing code.
As for the second part of the question - how you stop the timer is preferential. in such a small application (if this is its function in entirety) then simply stopping the timer within the event handler (or related method) would just do the trick, though in order to access the Timer instance you would declare it at a higher level in scope (i.e not bound within the scope of the click event handler).
Generally, the first thing you do is stop the timer in your event handler.
If you just want one timer then make it a form level variable, start it in your ButtonHide_Click, then at the top of your RevealForm method, stop the timer.
I have an app that I would like to update on an interval. I am looking for maybe some type of if statement or try - catch statement. I already have a foreach statement in the same class, but i dont think I can put in there? I would also like to set it up so that the user can change the refresh rate. Any help is appreciated. Thanks
Here is the method that I would like to put the timer in...
private void _UpdatePortStatus(string[] files)
{
foreach (string file in files)
{
PortStatus ps = new PortStatus();
ps.ReadXml(new StreamReader(file));
if (!_dicPortStatus.ContainsKey(ps.General[0].Group))
{
_dicPortStatus.Add(ps.General[0].Group, ps);
}
PortStatus psOrig = _dicPortStatus[ps.General[0].Group];
foreach (PortStatus.PortstatusRow psr in ps.Portstatus.Rows)
{
DataRow[] drs = psOrig.Portstatus.Select("PortNumber = '" + psr.PortNumber + "'");
if (drs.Length == 1)
{
DateTime curDt = DateTime.Parse(drs[0]["LastUpdateDateTimeUTC"].ToString());
DateTime newDt = psr.LastUpdateDateTimeUTC;
if (newDt > curDt)
{
drs[0]["LastUpdateDateTimeUTC"] = newDt;
}
}
else if (drs.Length == 0)
{
psOrig.Portstatus.ImportRow(psr);
}
else
{
throw new Exception("More than one of the same portnumber on PortStatus file: " + file);
}
}
}
}
Look at the System.Timer class. You basically set an interval (eg. 10000 milliseconds) and it will raise an event every time that interval time passes.
To allow the use to change the refresh rate, write a method that receives input from the user and use that to update the TimerInterval. Note that the TimerInterval is in miliseconds, so you may need to convert to that from whatever the user input.
So, from the example, the event will be raised every 10 seconds:
System.Timers.Timer aTimer = new System.Timers.Timer(10000); //10 seconds
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Enabled = true; // Starts the Timer
// Specify what you want to happen when the Elapsed event is raised
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//Perform update
_UpdatePortStatus(files);
}
UPDATE: In response to your posted code, it appears you simply want to call _UpdatePortStatus to update the port status at regular intervals (see the updated example above).
One important point you need to bear in mind though is that the Timer will run on a separate thread, and as such could raise the event again before it has finished running from the last time if it takes more than the interval time to run.
Use System.Timers.Timer, System.Threading.Timer or System.Windows.Forms.Timer ... depending on what exactly it is that you "would like to update on an interval."
See the following articles:
http://www.intellitechture.com/System-Windows-Forms-Timer-vs-System-Threading-Timer-vs-System-Timers-Timer/
http://www.yoda.arachsys.com/csharp/threads/timers.shtml
Your question is somewhat vague as there an many different methods of achieving what you want to do. However in the simplest terms you need to create a System.Threading.Timer that ticks on whatever frequency you define, for example:
private System.Threading.Timer myTimer;
private void StartTimer()
{
myTimer = new System.Threading.Timer(TimerTick, null, 0, 5000);
}
private void TimerTick(object state)
{
Console.WriteLine("Tick");
}
In this example the timer will 'tick' every 5 seconds and perform whatever functionality you code into the TimerTick method. If the user wants to change the frequency then you would destroy the current timer and initialise with the new frequency.
All this said, I must stress that this is the simplest of implementation and may not suit your needs.