Abstract function and timers - c#

I am pretty new to inheritance. Trying to implement a base class with a static timer. This timer will call an abstract function every time the time has elapsed. The reason is that two classes that inhereting from the base class will have a synchronized timers. Here is the code
Base class:
public abstract class UIControllers
{
public enum IndicatorColors
{
Green,
Red,
Yellow,
Blue
}
private static Timer UITimer;
public UIControllers()
{
EnableUITimer();
}
private int intervalInMillis = 500;
/// <summary>
/// Enables the timer responsible for UI effect in the GUI.
/// </summary>
private void EnableUITimer()
{
if (UITimer != null)
{
return;
}
UITimer = new Timer();
UITimer.Interval = intervalInMillis;
UITimer.Elapsed += UITimer_Elapsed;
UITimer.Start();
}
private void UITimer_Elapsed(object sender, ElapsedEventArgs e)
{
TimeElapsed();
}
/// <summary>
/// The function is being called when the time interval ellapsed
/// </summary>
protected abstract void TimeElapsed();
...
Derived class:
protected override void TimeElapsed()
{
....
}
It only works for one of my two classes that inheriting from the base class (whichever class was instantiated first it works for it).
Thanks

In EnableUITimer(), you wave off if the static instance has been created, so the only subclass instance that ever gets to give UITimer an event handler is the one that creates it -- the first one, as you noticed. The event handler is an instance method, a delegate.
Instead, do this:
private void EnableUITimer()
{
if (UITimer != null)
{
// If it already exists, give it a handler from this instance.
// Every instance that wants to be notified has to provide its own
// event handler.
UITimer.Elapsed += UITimer_Elapsed;
return;
}
UITimer = new Timer();
UITimer.Interval = intervalInMillis;
UITimer.Elapsed += UITimer_Elapsed;
UITimer.Start();
}

This section of code gets run 2x (once for each object instance)
public UIControllers()
{
EnableUITimer();
}
UITimer is static and null on first execution so ALL of EnableUITimers executes on the FIRST instance. With the second instance UITimer != null is true so EnableUITimer returns without creating the timer and wiring up UITImer_Elasped.
private void EnableUITimer()
{
if (UITimer != null)
{
return; // Exits on second instance
}
What you probably want to do is skip creating the timer if it is already instanced, but still wire up to the Elapsed event
private void EnableUITimer()
{
if (UITimer == null)
{
UITimer = new Timer();
UITimer.Interval = intervalInMillis;
UITimer.Start();
}
UITimer.Elapsed += UITimer_Elapsed;
}

Related

Unregister Events MultiCastDelegate Performance Problem

I have a problem: Our application has grown so far and therefore there is an object with many many EventHandlers. The point here is that removing them takes far more time, than adding them. This can be tested very fast:
Create a class with a
public event EventHandler
Make a second time and register to the event in first class like 300'000 times.
Here comes the interesting point: Registring needs like 0.1 seconds, whereas deregistring needs 5 minutes and it's growing almost exponentially.
Does anyone have a solution for that? The only one I found is to solve it over a WeakEventHandler (with it's downsides), but maybe there is another possiblity.
Example:
public class ClassWithValueChangedEvent
{
public event EventHandler ValueChanged;
public ClassWithValueChangedEvent()
{
}
}
public class MainWindowViewModel
{
public MainWindowViewModel()
{
DateTime start = DateTime.Now;
var classInstance = new ClassWithValueChangedEvent();
for (int i = 0; i < 300000; i++)
{
classInstance.ValueChanged += ClassWithValueChangedOnValueChanged;
}
Debug.WriteLine($"Elapsed Time: {(DateTime.Now - start).TotalSeconds}");
start = DateTime.Now;
for (int i = 0; i < 300000; i++)
{
classInstance.ValueChanged -= ClassWithValueChangedOnValueChanged;
}
Debug.WriteLine($"Elapsed Time: {(DateTime.Now - start).TotalSeconds}");
If we need to remove all event handlers
What I would do is that I would create an Unset method inside the class that nullifies the ValueChanged event handler like bellow:
public class ClassWithValueChangedEvent
{
public event EventHandler ValueChanged;
public void Unset()
{
ValueChanged = null;
}
}
Then, when needed I would do:
classInstance.Unset();
This is almost instantaneous.
If we need to remove individual event handlers
The process bellow is much more complicated and I don't know if I would choose it if I was in such need. The idea is that we create a custom list and we invoke the handlers manually:
public class ClassWithValueChangedEvent
{
private List<EventHandler> eventHandlers = new List<EventHandler>();
public void SetEventHandler(EventHandler evt)
{
eventHandlers.Add(evt);
}
public void UnsetEventHandler(EventHandler evt)
{
eventHandlers.Remove(evt);
}
public void UnsetAll()
{
eventHandlers.Clear();
}
public void CallEventHandlers(object? sender, EventArgs e)
{
eventHandlers.All(p => { p(sender, e); return true; });
}
}
Then, the methods of this class can be called as:
classInstance.SetEventHandler(ClassWithValueChangedOnValueChanged);
classInstance.CallEventHandlers(null, null);
classInstance.UnsetEventHandler(ClassWithValueChangedOnValueChanged);
Removing 300000 event handlers takes around 9 seconds which is much faster than minutes. I guess also that there must be a much faster way to do something like that.
I solved this question in using the WeakEventManager<>.AddHandler() from microsoft, which does not immediately remove the event handlers. It did not matter in this case.

Windows Service- Can it run two separate tasks scheduled at different intervals

I have written a Windows Service which triggers email ONCE in a WEEK at specific time. The service runs perfectly fine. Code is shown below:
protected override void OnStart(string[] args)
{
this.Log("Simple Service Started");
this.ScheduleService();
}
protected override void OnStop()
{
this.Log("Simple Service Stopped");
this.Schedular.Dispose();
}
private Timer Schedular;
public void ScheduleService()
{
try
{
Schedular = new Timer(new TimerCallback(SchedularCallback));
// Code that schedules the Callback
}
}
private void SchedularCallback(object e)
{
try
{
// Scheduled Job code
}
}
Now I have another similar requirement where I have to trigger another email, but its schedule has to be ONCE in 2 WEEKS. Is there a way this job can be accommodated in the same service, or I have to write another service?
I once did a similar design in one of my projects.
Try having a base abstract "ScheduledTask" class that defines your timing behavior, and have it used by inherited tasks classes.
Here is what I did for timers, I think there's only little work to change it to a Scheduler.
internal abstract class TaskBase
{
/// <summary>
/// Task timer
/// </summary>
private readonly Timer _timer;
/// <summary>
/// Set refresh time
/// </summary>
protected int TimeRefreshSec { get; private set; }
/// <summary>
/// Loop of timePassed
/// </summary>
protected int TimePassed { get; private set; }
protected TaskBase(double refreshInterval)
{
TimeRefreshSec = (int) refreshInterval / 1000;
TimePassed = 0;
_timer = new Timer(refreshInterval) { AutoReset = true };
_timer.Elapsed += Tick;
}
private void Tick(object sender, ElapsedEventArgs e)
{
TimePassed += TimeRefreshSec;
Tick();
}
public void Start()
{
ResetTimer();
// Run the task once when starting instead of waiting for a full interval.
Tick();
OnStart();
}
public void Stop()
{
if (_timer.Enabled)
{
_timer.Stop();
OnStop();
}
}
protected virtual void ResetTimer()
{
TimePassed = 0;
if (_timer.Enabled) _timer.Stop();
_timer.Start();
}
/// <summary>
/// Implement here a specific behavior when task is stopped.
/// </summary>
protected abstract void OnStop();
/// <summary>
/// Implement here a specific behavior when task is started.
/// </summary>
protected abstract void OnStart();
/// <summary>
/// This method is executed each time the task's timer has reached the interval specified in the constructor.
/// Time counters are automatically updated.
/// </summary>
protected abstract void Tick();
}
and for the service :
public partial class MyService : ServiceBase
{
private readonly List<TaskBase> _tasks;
public MyService()
{
InitializeComponent();
// Add in this list the tasks to run periodically.
// Tasks frequencies are set in the corresponding classes.
_tasks = new List<TaskBase>
{
new InheritingTask(),
new OherInheritingTask()
};
}
protected override void OnStart(string[] args)
{
try
{
_tasks.ForEach(t => t.Start());
}
catch (Exception ex)
{
Stop();
}
}
protected override void OnStop()
{
_tasks.ForEach(t => t.Stop());
}
}
EDIT:
The code for a class inheriting TaskBase:
class InheritingTask: TaskBase
{
public InheritingTask()
: base(Settings.Default.InheritingTaskInterval) // In milliseconds
{
//TODO: Custom initialization here
}
protected override void Tick()
{
//TODO: Task logic here
}
protected override void OnStart()
{ }
protected override void OnStop()
{ }
protected override void ResetTimer()
{
//TODO: Custom reset logic here
base.ResetTimer();
}
}
You could easily make a 2nd Schedular that is started in ScheduleService that is set to go off in two weeks however a Timer that fires once a week or two is a horrible way to do this, if the computer reboots you loose your timer and the email you where waiting on will not get sent.
You need a database of some kind to store when the next event should fire to survive restarts of your program, use a library that stores and does the scheduling for you like Hangfire.
Yes, you can achieve this using multithreading, for example via Tasks or Backgroundworkers. With this you can start each timer on a different thread which executes your operation when the timer ticks. It would also be advisable to separate timer and execution on different threads - for example Backgroundworkers for Timer 1 and 2 and Backgroundworkers for Execution 1 and 2.

Subscribing to an event of a class that holds the override method of the class you reference

I am working with background workers to update a progress bar in a WPF UI I am working on. This background worker is getting its progress updates from multiple events that I am subscribed to, because the progress bar goes through several loading stages, and the percentages for those come from several places. here is some example/pseudo code explaining what I mean
The DoWork method of my background worker and the methods I am using to currently get some progress updates
// These are working fine
private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
orderProcessing.OnOrderProgress += OrderStatus;
orderProcessing.OnStandardOrderProgress += StandardOrderStatus;
orderProcessing.CreateOrders(orders);
}
private void OrderStatus(int currentCount, int totalItems, string Message)
{
if (totalItems > 0)
bw.ReportProgress(Convert.ToInt32(((double)currentCount / (double)totalItems) * 100),
Message);
}
private void StandardOrderStatus(int currentCount, int totalItems, string Message)
{
if (totalItems > 0)
bw.ReportProgress(Convert.ToInt32(((double)currentCount / (double)totalItems) * 100),
Message);
}
Some code from my order processing class
public abstract class OrderProcessing
{
public delegate void OrderProgress(int CurrentItems, int TotalItems, string Message);
public event MasterSalesOrder.StandardOrderProgress OnStandardOrderProgress;
public event OrderProgress OnOrderProgress;
public abstract List<MasterSalesOrder> CreateOrders(List<Order> orders);
}
Some code from the class that holds the override method for CreateOrders()
public abstract class OrderProcessingFile : OrderProcessing
{
public event OrderProgress OnOrderProgress;
public override List<MasterSalesOrder> CreateOrders(List<Order> orders)
{
//Does Some Stuff
foreach(var stuff in stuffs)
{
OnOrderProgress(currentCount, totalCount, "Message");
}
}
}
Since I am clearly not explaining this well, I need to get info from the OrderProcessingFiles OnOrderProgress event via the OrderProcessing class that I create in the DoWork method.I am unsure on how to subscribe to an event when my code never directly instantiates an instance of the OrderProcessingFile class and it is never directly referred to.
I have tried looking for answers but as my title will show I am having a hard time even wording this in a way to get useful results, and I am genuinely stuck on this one. Let me know if more detail is needed, I tried to strip down my code to only the relevant parts but I feel like I'm explaining this strangely.
I would recommend that you create a thread safe singleton progress manager. Then have each of the background workers contact it with updates. The progress manager will use a DispatcherTimer (which runs on the GUI thread) to update the GUI appropriately.
Raw example:
public static class StatusReportManager
{
// Standard singleton code to create the manager and access it.
// Start/create the dispatch time as well.
private static DispatcherTimer Timer { get; set; }
private static object _syncObject = new object();
public static void ReportStatus(...)
{
lock (_syncObject)
{
// Process any states and set instance properties for reading
// by the timer operation.
}
}
private void ShowStatus() // Used by the dispatch timer
{
lock (_syncObject)
{
// Do any updates to the GUI in here from current state.
}
}
}
I have realized what it is I was really trying to do and have thus found an answer. Using the method found in this MSDN article I have implemented the follow code:
This is my UI
private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
orderProcessing.OnOrderProgress += OrderStatus;
orderProcessing.CreateOrders(FanGlobal.BrandItems, FanGlobal.BrandItemMasterCustomers);
}
private void OrderStatus(object obj, OrderProcessing.OrderProgressEventArgs e)
{
if (e.totalCount > 0)
bw.ReportProgress(Convert.ToInt32(((double)e.currentCount / (double)e.totalCount) * 100),e.message);
}
This in my OrderProcessing class
public event EventHandler<OrderProgressEventArgs> OnOrderProgress;
public class OrderProgressEventArgs : EventArgs
{
public int currentCount;
public int totalCount;
public string message;
public OrderProgressEventArgs(int c, int t, string m)
{
currentCount = c;
totalCount = t;
message = m;
}
}
protected virtual void OnOrderProgressChanged(OrderProgressEventArgs e)
{
EventHandler<OrderProgressEventArgs> handler = OnOrderProgress;
if (handler != null)
{
handler(this, e);
}
}
public abstract List<MasterSalesOrder> CreateOrders(List<BrandItem> BrandItems = null, List<BrandItemMasterCustomer> BrandItemMasterCustomers = null);
and then I can use it in my child class OrderProcessingFile like so
public override List<MasterSalesOrder> CreateOrders(List<BrandItem> BrandItems = null, List<BrandItemMasterCustomer> BrandItemMasterCustomers = null)
{
//Do some Stuff
OnOrderProgressChanged(new OrderProgressEventArgs(count, totalItems, "Extracting"));
}
and everything is working like a charm. Sorry for the utterly confusing question and the apparent huge gap of knowledge I have/had, but hopefully this will help someone else in the future.

How to set up a application-wide Timer?

I want to have a timer in my windows phone 8 app, that´s counting/running independent of current shown page.
It should connect to server - when possible in a UI independet task/thread - and store data in a global object/list.
The Independence from current shown page is my point.
I tried following in App.xaml.cs:
public partial class App : Application
{
// creating timer instance
DispatcherTimer gAppTimer = new DispatcherTimer();
// timer interval specified as 1 minute
gAppTimer.Interval = TimeSpan.FromSeconds(60);
// Sub-routine OnTimerTick that will be called at specified intervall
gAppTimer.Tick += OnTimerTick;
// starting the timer
gAppTimer.Start();
public void OnTimerTick(Object sender, EventArgs args)
{
// text box property is set to current system date.
// ToString() converts the datetime value into text
MessageBox.Show("TIMER fired");
}
:
:
But this doesn´t work. Than I tried just declaring the object in App.xaml.cs:
public partial class App : Application
{
// creating timer instance
DispatcherTimer gAppTimer = new DispatcherTimer();
public void OnTimerTick(Object sender, EventArgs args)
{
// text box property is set to current system date.
// ToString() converts the datetime value into text
MessageBox.Show("TIMER fired");
}
:
:
And on my startpage.xaml.cs:
// timer interval specified as 1 minute
App.gAppTimer.Interval = TimeSpan.FromSeconds(60);
// Sub-routine OnTimerTick that will be called at specified intervall
App.gAppTimer.Tick += OnTimerTick;
// starting the timer
App.gAppTimer.Start();
But this doesn´t work, too.
Any ideas how to handle my Problem? What I don´t want to use is a Background Task, because it runs only every 30 minutes. My solution should only run, if the app is "active" (in foreground).
That's normally done using a static or singleton class. Both will be global and you'll have access to them from every page.
Also, the DispatcherTimer invokes it's TimerTick method on the UI thread. If you don't need to be in the UI thread, you should use a System.Threading.Timer, which invokes a method in a background thread.
Here's an example:
public static class SomeManager {
private static Timer gAppTimer;
private static object lockObject = new object();
public static void StartTimer() {
if (gAppTimer == null) {
lock (lockObject) {
if (gAppTimer == null) {
gAppTimer = new Timer(OnTimerTick, null, 60 * 1000, 60 * 1000);
}
}
}
}
public static void StopTimer() {
if (gAppTimer != null) {
lock (lockObject) {
if (gAppTimer != null) {
gAppTimer.Change(Timeout.Infinite, Timeout.Infinite);
gAppTimer = null;
}
}
}
}
private static void OnTimerTick(object state) {
Action();
}
public static void Action() {
// Do what you need to do
}
}
Just call SomeManager.StartTimer() from your first page or from App.xaml.cs and the timer will start.
Update
I updated the code a little:
Renamed the Initialize method to StartTimer.
Added StopTimer method which stops the timer. You can then start it again by calling SomeManager.StartTimer.
Added Action method which is the one actually donig the work. You can invoke it from anywhere, anytime.
Note: the the timer will call this method in a background thread and you should do the same using something like Task.Run(() => SomeManager.Action());
Added a lock to ensure that the Start/Stop methods will not throw exceptions if invoked from multiple threads at the same time.
I'm not sure how you have arranged your code, but as I've tried:
public partial class App : Application
{
public static PhoneApplicationFrame RootFrame { get; private set; }
public DispatcherTimer gAppTimer = new DispatcherTimer();
public void OnTimerTick(Object sender, EventArgs args)
{
MessageBox.Show("TIMER fired");
}
public App()
{
gAppTimer.Interval = TimeSpan.FromSeconds(2);
// Sub-routine OnTimerTick that will be called at specified intervall
gAppTimer.Tick += OnTimerTick;
// starting the timer
gAppTimer.Start();
// rest of the code
the above code works. MessageBox shows every 2 seconds, if you had declared your DispatcherTimer as public, then you will be able to access it like this:
(App.Current as App).gAppTimer.Stop();
Note also that depending on what you want to achieve you may also use System.Threading.Timer.
On the other hand you may also think of using public static DispatcherTimer somewhere.

C# - Memory leak when passing an event as parameter to a subclass

during the last days I tracked down a memory leak in our application. I know the idea of the developer, who wrote this code, but I am not really about why the leak occurs. The idea was to have a class, which contains an event. The class will instantiate another class, which shall add a event handler to the event in the Init-method and removes it, calling the Stop-method. The problem is, that the event isn't removed from the main class and the InvocationTargetList is growing and growing.
Here is an example source code, which shows the problem:
public class SampleEventArgs
{
public SampleEventArgs(string s) { Text = s; }
public String Text { get; private set; }
}
public class MainClass
{
public delegate void SampleEventHandler(object sender, SampleEventArgs e);
public event SampleEventHandler SampleEvent;
public SubClass m_SubClass = new SubClass();
public MainClass()
{
for (int i = 0; i < 10000; i++)
{
m_SubClass.Init(ref SampleEvent);
m_SubClass.Close();
}
if (SampleEvent != null)
Console.WriteLine("SampleEvent InvocationTargetList length: {0}", SampleEvent.GetInvocationList().Length);
Console.ReadKey();
}
}
public class SubClass
{
public event MemoryLeakTest.MainClass.SampleEventHandler m_Subscription;
public void Init(ref MainClass.SampleEventHandler SampleEvent)
{
SampleEvent += NewEvent;
m_Subscription = SampleEvent;
}
public void Close()
{
m_Subscription -= NewEvent;
}
public void NewEvent(object sender, SampleEventArgs e)
{
}
}
Well, I already fixed the problem by passing the class to the Init and Stop method and also implemented the IDisposeable pattern, but I am not 100% sure, why the code above produces the memory leak. Is it caused, because assigning the SampleEvent to m_Suscription will create a copy of the event and so the event will only be removed from the m_Subscription variable in the Stop method? Any ideas?
Well, we already know delegates are immutable and that's why you used ref parameter to subscribe event.
Now look this method closely
public void Close()
{
m_Subscription -= NewEvent;
}
You actually unsubscribe from a copy, and not from original delegate which is in MainClass. In other words you're re-assigning the field in sub class only not the field in main class.

Categories