Rate limiting on the KeyUp event handler in C# - c#

I'm wanting to validate the input on a text field as a user types. This functionality works fine, however I would like to rate limit the validation as it's hitting an external API. I'd like to only perform a validation after a user has not typed for 750ms.
ATM I'm simply using this:
private void Configure_Load(object sender, EventArgs e)
{
endpointBox.KeyUp += EndpointBox_KeyUp;
}
void EndpointBox_KeyUp(object sender, KeyEventArgs e)
{
TestHTTP200(endpointBox.Text);
}

Use a Timer Control
System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();
private void Configure_Load(object sender, EventArgs e)
{
endpointBox.KeyUp += EndpointBox_KeyUp;
myTimer.Tick +=new EventHandler(OnTimedEvent); //EDIT: should not be `ElapsedEventHandler`
myTimer.Interval=750;
}
void EndpointBox_KeyUp(object sender, KeyEventArgs e)
{
myTimer.Stop();
myTimer.Start();
}
private void OnTimedEvent(Object myObject,EventArgs myEventArgs)
{
myTimer.Stop();
TestHTTP200(endpointBox.Text);
}

You would want a method equal to JavaScript's SetTimeout method. This can be cancelled when the user provides more input:
Code taken from here.
public static IDisposable SetTimeout(Action method, int delayInMilliseconds)
{
System.Timers.Timer timer = new System.Timers.Timer(delayInMilliseconds);
timer.Elapsed += (source, e) =>
{
method();
};
timer.AutoReset = false;
timer.Enabled = true;
timer.Start();
// Returns a stop handle which can be used for stopping
// the timer, if required
return timer as IDisposable;
}
You can then use this in your key up handler:
void EndpointBox_KeyUp(object sender, KeyEventArgs e)
{
IDisposable timeout = SetTimeout(() => TestHTTP200(endpointBox.Text), 750);
if (this.currentTimeout != null) {
this.currentTimeout.Dispose();
this.currentTimeout = timeout;
}
}
This is the basic principle at least, every time the user types you reinitiate a 750ms timeout to do your thing, and cancel any pending timers.
Update: complete code sample:
public partial class Form1 : Form
{
private IDisposable currentTimeout;
public Form1()
{
InitializeComponent();
}
private void EndpointBox_KeyUp(object sender, KeyEventArgs e)
{
IDisposable timeout = TimerHelper.SetTimeout(() => TestHTTP200(EndpointBox.Text), 750);
if (this.currentTimeout != null)
{
this.currentTimeout.Dispose();
this.currentTimeout = timeout;
}
}
private void TestHTTP200(string text)
{
//...
}
}
public class TimerHelper
{
public static IDisposable SetTimeout(Action method, int delayInMilliseconds)
{
System.Timers.Timer timer = new System.Timers.Timer(delayInMilliseconds);
timer.Elapsed += (source, e) =>
{
method();
};
timer.AutoReset = false;
timer.Enabled = true;
timer.Start();
// Returns a stop handle which can be used for stopping
// the timer, if required
return timer as IDisposable;
}
}

using System;
namespace Azine_Library.Misc
{
/// <summary>
/// Represents a way to delay something, eg. something an event handler does, update-ion of a control, object or to run a method, This class '<see cref="DelayUpdate"/>'
/// is intended to be used as a delayer of some sort and contains an event, '<see cref="PushUpdate"/>' that would be subcribed to an event handler where then the code
/// intended to be delayed would go. This object also contains a method, '<see cref="delay"/>' that when called delays the code written/located within the event handler
/// that is handling the '<see cref="PushUpdate"/>' event. The method, <see cref="delay"/> should be called from an event handler or a method of some sort that would orginally
/// execute the code written/located within the event handler described above also. An example of how this object can interact with another object is described and documented in great detail
/// within the documentation for "Azine_Library", also an example program is available with the documentation.
/// </summary>
public class DelayUpdate
{
// Written, 17.06.2017
#region Fields / Properties
/// <summary>
/// Occurs when the provided time (interval:) has elapsed
/// </summary>
public event EventHandler PushUpdate;
/// <summary>
/// READONLY. the amount of times the timer has ticked since the last call to delay, (DelayUpdate.delay).
/// </summary>
public int updateCounter
{
get;
private set;
}
/// <summary>
/// The amount of time [this] waits for until it pushes the update. (Milliseconds). default value: '500'.
/// </summary>
public int interval
{
get;
set;
}
/// <summary>
/// Holds the amount of times [this] raises the "DelayUpate.PushUpdate" event every call to DelayUpdate.delay() method. default value: '1'.
/// </summary>
public int updatesPerPush
{
get;
set;
}
private System.Diagnostics.Stopwatch stopWatch;
private System.Windows.Forms.Timer timer;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of type, 'DelayUpdate'; sets the classes' properties to the defaults.
/// </summary>
public DelayUpdate()
{
//Initializing Variables
this.updateCounter = 0;
this.interval = 500;
this.updatesPerPush = 1;
this.stopWatch = new System.Diagnostics.Stopwatch();
this.timer = new System.Windows.Forms.Timer();
//Sub-ing Events
this.timer.Tick += this.Timer_Tick;
}
#endregion
#region Methods
/// <summary>
/// Delays the raising of the event, PushUpdate; call this method when a property of an object has changed. eg, TextBox.TextChanged => DelayUpdate.delay();
/// </summary>
public void delay()
{
// Written, 13.06.2017
this.timer.Start();
this.stopWatch.Restart();
this.updateCounter = 0;
}
#endregion
#region Events
/// <summary>
/// Raises the 'DelayUpdate.PushUpdate' event.
/// </summary>
private void onPushUpdate()
{
//Written, 26.05.2017 : 5:22pm
if (PushUpdate != null)
PushUpdate.Invoke(this, new EventArgs());
}
#endregion
#region Event Handlers
private void Timer_Tick(object sender, EventArgs e)
{
// Written, 13.06.2017
if (this.stopWatch.ElapsedMilliseconds > this.interval)
{
if (this.updateCounter < this.updatesPerPush)
{
this.timer.Stop();
this.onPushUpdate();
}
this.updateCounter++;
}
}
#endregion
}
}
And this is how you would use this class, DelayUpdate.cs:
Say you have a WinForm that searches a directory for files which has a textbox called, "search_textBox" and has a textChanged event handler attached, :
namespace DelayUpdateExample
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.search_textBox.TextChanged += this.Search_textBox_TextChanged;
}
private void Search_textBox_TextChanged(object sender, EventArgs e)
{
}
}
}
You would make a reference to the class, DelayUpdate.cs and initialize it. Subscribe to the DelayUpdate.PushUpdate event like so:
private DelayUpdate delayUpdate;
public Form1()
{
InitializeComponent();
this.delayUpdate = new DelayUpdate()
{
interval = 500,
updatesPerPush = 1,
};
this.delayUpdate.PushUpdate += this.DelayUpdate_PushUpdate;
this.search_textBox.TextChanged += this.Search_textBox_TextChanged;
}
private void DelayUpdate_PushUpdate(object sender, EventArgs e)
{
throw new NotImplementedException();
}
Within the textChanged event handler you would make a call to DelayUpdate.delay() like so..
private void Search_textBox_TextChanged(object sender, EventArgs e)
{
this.delayUpdate.delay();
}
And the code that you would want to delay would then go in the DelayUpdate_PushUpdate(object, EventArgs) that you subscribed to. like so:
private void DelayUpdate_PushUpdate(object sender, EventArgs e)
{
// You would search the directory here..
// Code that you want to delay would go here.
}

Related

How do I make a windows form close after 30 minutes? | Visual Studio C# Windows Forms App .Net Framework

I want a code that makes 'Form 2' close after 30 minutes and 'Form 1' to show up.
private void button1_Click_1(object sender, EventArgs e)
MessageBox.Show("Thank you for using Crystal X!", "Success");
this.Hide();
CrystalX main = new CrystalX();
main.Show();
(Code to wait 30 minutes)
this.Hide();
Form1 main = new Form1();
main.Show();
One method is to setup a Timer and Action.
Action in your form
public void FormWork()
{
this.Hide();
Form1 main = new Form1();
main.Show();
TimerHelper.Stop();
}
In the same form, your altered Click event
private void button1_Click_1(object sender, EventArgs e)
{
MessageBox.Show("Thank you for using Crystal X!", "Success");
this.Hide();
CrystalX main = new CrystalX();
main.Show();
TimerHelper.Start(FormWork);
}
Create a new class named ActionContainer in the same project.
public class ActionContainer
{
/// <summary>
/// Action to perform
/// </summary>
public Action Action { get; set; } = () => { };
}
Now for the worker class named TimerHelper. Note the event Message is completely optional, used more so to see when code is executed. Change the namespace to your project's namespace.
using System;
using System.Threading;
using Timer = System.Threading.Timer;
namespace WorkingWithTimer.Classes
{
public class TimerHelper
{
/// <summary>
/// How long between intervals, currently 30 minutes
/// </summary>
private static int _dueTime = 1000 * 60 * 30;
private static Timer _workTimer;
public static ActionContainer ActionContainer;
/// <summary>
/// Text to display to listener
/// </summary>
/// <param name="message">text</param>
public delegate void MessageHandler(string message);
/// <summary>
/// Optional event
/// </summary>
public static event MessageHandler Message;
/// <summary>
/// Flag to determine if timer should initialize
/// </summary>
public static bool ShouldRun { get; set; } = true;
/// <summary>
/// Default initializer
/// </summary>
private static void Initialize()
{
if (!ShouldRun) return;
_workTimer = new Timer(Dispatcher);
_workTimer.Change(_dueTime, Timeout.Infinite);
}
/// <summary>
/// Initialize with time to delay before triggering <see cref="Worker"/>
/// </summary>
/// <param name="dueTime"></param>
private static void Initialize(int dueTime)
{
if (!ShouldRun) return;
_dueTime = dueTime;
_workTimer = new Timer(Dispatcher);
_workTimer.Change(_dueTime, Timeout.Infinite);
}
/// <summary>
/// Trigger work, restart timer
/// </summary>
/// <param name="e"></param>
private static void Dispatcher(object e)
{
Worker();
_workTimer.Dispose();
Initialize();
}
/// <summary>
/// Start timer without an <see cref="Action"/>
/// </summary>
public static void Start()
{
Initialize();
Message?.Invoke("Started");
}
/// <summary>
/// Start timer with an <see cref="Action"/>
/// </summary>
public static void Start(Action action)
{
ActionContainer = new ActionContainer();
ActionContainer.Action += action;
Initialize();
Message?.Invoke("Started");
}
/// <summary>
/// Stop timer
/// </summary>
public static void Stop()
{
_workTimer.Dispose();
Message?.Invoke("Stopped");
}
/// <summary>
/// If <see cref="ActionContainer"/> is not null trigger action
/// else alter listeners it's time to perform work in caller
/// </summary>
private static void Worker()
{
Message?.Invoke("Performing work");
ActionContainer?.Action();
}
}
}
Another example, simply moving the second form and timer declarations out to form/class level in the first form:
private CrystalX main = null;
private System.Windows.Forms.Timer tmr = null;
private void button1_Click(object sender, EventArgs e)
{
this.Hide();
if (main == null || main.IsDisposed)
{
main = new CrystalX();
main.FormClosed += Main_FormClosed;
}
if (tmr == null)
{
tmr = new System.Windows.Forms.Timer();
tmr.Tick += Tmr_Tick;
tmr.Interval = (int)TimeSpan.FromMinutes(30).TotalMilliseconds;
}
main.Show();
tmr.Start();
}
private void Main_FormClosed(object sender, FormClosedEventArgs e)
{
if (tmr != null && tmr.Enabled)
{
tmr.Stop();
}
this.Show();
main = null;
}
private void Tmr_Tick(object sender, EventArgs e)
{
if (main != null && !main.IsDisposed)
{
main.Close();
}
}

Progress bar does not update on separate form from VSTO addin

On button click in Word VSTO addin, I want to show the form with progress bar and update its value.
Even though I used BackgroundWorker and its events (DoWork, ProgressChanged), progress of the progress bar does not update accordingly
private void extractDataButton_Click(object sender, RibbonControlEventArgs e)
{
//On button click of addin
ProgressNotifier progressNotifier = new ProgressNotifier();
progressNotifier.Show();
progressNotifier.UpdateProgressBar(10);
// Does the work which lasts few seconds
HandleRetrievedData(data);
progressNotifier.UpdateProgressBar(100);
progressNotifier.Close();
}
// Progress bar form
public partial class ProgressNotifier : Form
{
public ProgressNotifier()
{
InitializeComponent();
}
public void UpdateProgressBar(int progress)
{
backgroundWorker1.ReportProgress(progress);
progressBar_extractionProgress.Update();
}
private void backgroundWorker1_ProgressChanged(object sender,
ProgressChangedEventArgs e)
{
this.progressBar_extractionProgress.Value = e.ProgressPercentage;
}
}
Although this is an older style using delegates, you might need a check that the form is available for updating. Below is older code - there are examples using newer syntax not requiring delegates - but generally illustrates a resolve.
private delegate void StatusMessage();
/// <summary>
/// Simple methods for setting active cube list before connecting
/// </summary>
private void SetDefaultNode()
{
if (this.ActiveCubeStatus.InvokeRequired)
{
StatusMessage d = new StatusMessage(SetDefaultNodeDirect);
this.Invoke(d);
}
else
{
SetDefaultNodeDirect();
}
}
/// <summary>
/// Simple methods for setting active cube list before connecting
/// </summary>
private void SetDefaultNodeDirect()
{
//clears treeveiw
ClearActiveCubes();
//create default inactive node
TreeNode nodeDefault = new TreeNode();
nodeDefault.Name = "Waiting";
nodeDefault.Text = "Waiting on connection...";
this.ActiveCubeStatus.Nodes.Add(nodeDefault);
nodeDefault = null;
}

DispatcherTimer ticking not working when started in ThreadPool.QueueUserWorkItem() method

I've created a TimerManager class for my WPF application.
This class handles the start and stop the dispatcher timer.
Here is the class:
public static class TimerManager
{
static DispatcherTimer disTimer;
static Model m = Model.GetInstance();
static TimerManager()
{
disTimer = new DispatcherTimer();
disTimer.Tick += disTimer_tick;
disTimer.Interval = new TimeSpan(0, 0, 1);
}
public static void StartTimer()
{
disTimer.Start();
}
public static void StopTimer()
{
disTimer.Stop();
}
private static void disTimer_tick(object sender, EventArgs e)
{
m.Tick++;
}
}
And I've created a Model class that represents the ticking in the UI.
(Binding in MainWindow.xaml -> xy textbox text field "{Binding Tick}").
class Model : INotifyPropertyChanged
{
private Model()
{
}
static Model instance;
public static Model GetInstance()
{
if (instance == null)
{
instance = new Model();
}
return instance;
}
int tick;
public event PropertyChangedEventHandler PropertyChanged;
public void OnNotifyPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, e);
}
}
public int Tick
{
get
{
return tick;
}
set
{
tick = value;
OnNotifyPropertyChanged();
}
}
}
And here is the MainWindow class:
Model m;
public MainWindow()
{
InitializeComponent();
m = Model.GetInstance();
this.DataContext = m;
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(o =>
{
TimerManager.StartTimer();
});
//TimerManager.StartTimer();
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
TimerManager.StopTimer();
}
When I click the start button I use the ThreadPool.QueueUserWorkItem() method. In that method, I start the timer but the timer tick is not run at every one second.
When I don't use ThreadPool this works. But this solution is not good for me; ThreadPool is important for me because I use an HTTP web server (in local).
My question is: why is the ticking not working if I use ThreadPool?
The DispatcherTimer object has thread affinity. That is, it is tied to a specific thread. In particular, it is designed specifically to raise its Tick event in the thread in which it was created, using the Dispatcher for that thread.
Your ThreadManager class's static constructor will be called when the type is first used. In your non-working example, this occurs in the queued work item method, causing the static constructor to be executed in the thread pool thread used to execute that work item method. This in turn causes the DispatcherTimer object you create to be owned by that thread, and to have its Tick event raised in that thread by the Dispatcher for that thread.
Except, thread pool threads don't have Dispatchers. So there's no Dispatcher there to raise the Tick event for the DispatcherTimer object. Even if there was, without a call to Application.Run() to have the dispatcher loop executed, the Dispatcher wouldn't actually get to dispatch anything, including the Tick event.
What you need is to make sure that when you create the DispatcherTimer object, the code that creates that object is executed in the dispatcher thread, which is your main UI thread.
There are a couple of ways to do that. IMHO, the best way is to make your ThreadManager class not a static class and to create an instance of it in your MainWindow constructor. For example:
class TimerManager
{
DispatcherTimer disTimer;
Model m = Model.GetInstance();
public TimerManager()
{
disTimer = new DispatcherTimer();
disTimer.Tick += disTimer_tick;
disTimer.Interval = new TimeSpan(0, 0, 1);
}
public void StartTimer()
{
disTimer.Start();
}
public void StopTimer()
{
disTimer.Stop();
}
private void disTimer_tick(object sender, EventArgs e)
{
m.Tick++;
}
}
and:
public partial class MainWindow : Window
{
TimerManager _timerManager = new TimerManager();
public MainWindow()
{
InitializeComponent();
this.DataContext = Model.GetInstance();
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(o =>
{
_timerManager.StartTimer();
});
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
_timerManager.StopTimer();
}
}
Since you know your MainWindow object has to be created in the dispatcher thread, and you know that non-static field initialization happens at the same time the constructor is called, in that same dispatcher thread, the above ensures that your TimerManager object is created in the dispatcher thread.
This gives you complete control over the lifetime of the TimerManager object, particularly when it's created but of course also when it can be discarded. Given the nature of the DispatcherTimer object itself, it's my opinion that this is better than maintaining a statically-held instance.
This approach also gives you the option of having a manager object for each dispatcher thread (in rare cases, a program might have more than one…you should try very hard to avoid getting into that situation, but it can be useful for types to at least be compatible with such a situation).
That said, if you really want to keep the static implementation, you can do that by providing a method that can be called explicitly when you want to initialize the class, so you can make sure that the initialization happens in the right thread:
static class TimerManager
{
static DispatcherTimer disTimer;
static Model m = Model.GetInstance();
public static void Initialize()
{
disTimer = new DispatcherTimer();
disTimer.Tick += disTimer_tick;
disTimer.Interval = new TimeSpan(0, 0, 1);
}
public static void StartTimer()
{
disTimer.Start();
}
public static void StopTimer()
{
disTimer.Stop();
}
private static void disTimer_tick(object sender, EventArgs e)
{
m.Tick++;
}
}
Then in your MainWindow class:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = Model.GetInstance();
StaticTimerManager.Initialize();
}
private void startButton_Click(object sender, RoutedEventArgs e)
{
ThreadPool.QueueUserWorkItem(o =>
{
StaticTimerManager.StartTimer();
});
}
private void stopButton_Click(object sender, RoutedEventArgs e)
{
StaticTimerManager.StopTimer();
}
}
All you need to do here is make sure you call the Initialize() method from the main UI thread where you actually have a running dispatcher, before you attempt to call either of the other two static methods in the class.
This approach could also be made to work with multiple threads (i.e. if you have more than one dispatcher thread), but it would be trickier, especially if you want to be able to call the StartTimer() method from a different thread that actually owns the timer object. I'd recommend against the static class approach if you really did wind up in that situation.

Replacing the System.Timers.Timer.Elapsed event when inheriting System.Timers.Timer

I'm creating a new class so that I can make the System.Timers.Timer class fit my needs just a little bit better. I create my new class like so...
using System.Timers;
class BtElapsedEventArgs : ElapsedEventArgs
{
//My extras
}
namespace MyGreatNewTimer
{
class BetterTimer : Timer
{
}
}
Now I simply want to replace the Elapsed event that fires elsewhere.
private void TestTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Timer has elapsed
}
I want it to produce the following...
private void TestTimer_Elapsed(object sender, BtElapsedEventArgs e)
{
//Timer has elapsed
}
How can I go about doing this?
If I understand your question correctly, you can follow How to: Publish Events that Conform to .NET Framework Guidelines (C# Programming Guide) and create your own Elapsed event and hide the original Epalsed event:
namespace MyGreatNewTimer
{
class BtElapsedEventArgs : EventArgs
{
public DateTime SignalTime { get; set; }
//Some other properties
}
class BetterTimer : Timer
{
new public event EventHandler<BtElapsedEventArgs> Elapsed;
public BetterTimer()
{
base.Elapsed += BetterTimer_Elapsed;
}
void BetterTimer_Elapsed(object sender, ElapsedEventArgs e)
{
var handler = this.Elapsed;
if(handler!=null)
{
var bte = new BtElapsedEventArgs() { SignalTime = e.SignalTime};
//Set other properties, then fire the event
handler(sender, bte);
}
}
}
}

How to implement dispatcher timer in class and call it

So I'm working on an application that will need a timer on every page counting by the second. I figured it would be best to have the actual function on a class and have it called by the pages that need it. What I do know is how to get the timer working in a page... What baffles me is how to get it working in a class.
Needless to say, I'm failing.
Here's what I've done in the class:
namespace Masca
{
public class timer
{
public void StartTimer()
{
System.Windows.Threading.DispatcherTimer dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
DateTime datetime = DateTime.Now;
}
And what I've done in a page I need the timer in
namespace Masca
{
public partial class signup : Elysium.Controls.Window
{
public timer timer;
public signup(string Str_Value)
{
InitializeComponent();
tag.Text = Str_Value;
}
public void dispatcherTimer_Tick(object sender, EventArgs e)
{
DateTime datetime = DateTime.Now;
this.doc.Text = datetime.ToString();
}
I can't get the 'dispatcherTimer_Tick' event to know it's supposed to get it's instructions on how to work from the class 'timer'.
Any ideas on how to do this?
You probably want to add an event to your timer class:
public class timer
{
public event EventHandler TimerTick;
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
if (TimerTick != null)
TimerTick(this, null);
}
So that in your Window you can just listen to this event.
You will need to expose either your own event or delegate from your timer class. The external classes subscribe to this event/delegate and you raise/call it from the dispatcherTimer_Tick method in your timer class.
I would do something like this in your timer class:
public delegate void TimeUp(); // define delegate
public TimeUp OnTimeUp { get; set; } // expose delegate
...
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
DateTime datetime = DateTime.Now;
if (OnTimeUp != null) OnTimeUp(); // call delegate
}
And from outside the class:
public timer timer;
...
timer.OnTimeUp += timerOnTimeUp;
private void timerOnTimeUp()
{
// time is up
}

Categories

Resources