Replacing the System.Timers.Timer.Elapsed event when inheriting System.Timers.Timer - c#

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);
}
}
}
}

Related

C# - How to update Main UI from a thread in another class

I'm actually learning (the hard way) c# and been fighting for days with a problem :
I'm writing my first c# application with WPF (dotNet 4.0). When I click on a button, a BackgroundWorker thread is used and call a method from an external class, this way my UI don't freeze -> my method run as expected.
Then I tried to update a ListView control from thos external class to get some kind of progress (text) and I miserably failed.
I understand that I need to use a delegate and the dispatcher to update my control.
I tried to use the solution offered here How to update UI from another thread running in another class . (I cannot comment on it because of my low rep) and I miss some parts of the puzzle.
What the YourEventArgs(status) is referring to ? I just don't get the way to fire an event and pass the content back to my UI while my method is running inside the BGW.
So far I have this piece of code (Updated from answer):
namespace AppMain
{
public partial class MainWindow
{
BackgroundWorker AppWorker = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
AppWorker.WorkerSupportsCancellation = true;
AppWorker.DoWork += AppWorker_DoWork;
AppWorker.RunWorkerCompleted += AppWorker_RunWorkerCompleted;
}
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
lstTest.Items.Add("Processing data...");
AppWorker.RunWorkerAsync();
}
public void AppWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
SetXmlData xml = new SetXmlData();
xml.ProgressUpdate += (s, evt) =>
{
Dispatcher.BeginInvoke((Action)(() =>
{
lstTest.Items.Add("this is a test : " + evt.myData); //how to retrieve the myData property from evt ?
}));
};
xml.FlushData();
}
public void AppWorker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
{
if (!(e.Cancelled))
{
lstTest.Items.Add("Done");
}
else
{
MessageBox.Show("Cancelled");
}
}
}
}
SetXmlData.cs
namespace AppMain
{
public class SetXmlData
{
public event EventHandler ProgressUpdate;
//update method
public void update(object input)
{
if (ProgressUpdate != null)
ProgressUpdate(this, new YourEventArgs { myData = (string)input });
}
//calculation method
public void FlushData()
{
MessageBox.Show("this is a test !");
update("test");
}
}
public class YourEventArgs : EventArgs
{
public string myData { get; set; }
}
}
Thanks for your help.
You can simply Invoke the ProgressUpdate event from the FlushData() method.
Simply call:
If (ProgressUpdate !=null )
{
ProgressUpdate(this,new YourEventArgs())
}
this is the source instance where the event originated from.
You could just create YourEventArgs by inheriting from EventArgs class.
public class YourEventArgs : EventArgs
{
//Put any property that you want to pass back to UI here.
}
When the event gets raised in the UI:
RaiseEvent.ProgressUpdate += (s, e) =>
{
Dispatcher.BeginInvoke((Action)(() =>
{
lstTest.Items.Add("this is a test : ");
//Add items to your UI control here...
}));
};
e will be of type YourEventArgs.
On a side note, you should never touch UI thread from a diffent thread (like background worker thread in your example). Since your event-handler already does the Dispatcher.BeginInvoke, that's safe.
Also, your ProgressUpdate event should be inside of your class SetXmlData.
try get;set; Example:
Form1:
public partial class Form1 : Form
{
static public string gettext { get; set; }
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Class1.send(); //call to class function
textBox1.Text = gettext; //items.add(gettext)
}
}
Class1:
class Class1
{
static public void send()
{
Form1.gettext = "Marko"; //Set gettext to string "Marko"
}
}

C# WPF - How to auto refresh the UI after run it

I created in the XAML a simple Label called TbTimer
I made the following code:
class Level2
{
public Level2()
{
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1);
timer.Tick += timer_Tick;
}
public int counter;
public void timer_Tick(object sender, EventArgs e)
{
counter++;
}
public DispatcherTimer timer;
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
lvl2 = new Level2();
}
private void MenuItemMedium_Click(object sender, RoutedEventArgs e)
{
lvl2.timer.Start();
TbTimer.Content = lvl2.counter.ToString();
}
}
Then I have another button, and I call TimerUpdater when that button is clicked.
When I run the program and I click the button, I can see that the content of the TextBlock shows the number 1... and it does not continue to run the numbers - when I click the button again after 5 seconds it shows the number 6.
So I guess the timer is running fine behind the scenes, but the content of the TextBlock is updated only when I click the button.
What should I do to make the TextBlock content update the seconds without clicking the button? Hope my explanation and question is clear.
With your modified code, the answer changes completely. I apologize for the dramatic change in content. The "simplest" way to accomplish this would be to add an event for the counter updating and have your UI subscribe to it. Something like:
class Level2
{
public event Action<int> CounterUpdated;
...
public void timer_Tick(object sender, EventArgs e)
{
counter++;
if (CounterUpdated != null)
CounterUpdated(counter);
}
}
public class MainWindow
{
public MainWindow()
{
InitializeComponent();
lvl2 = new Level2();
lvl2.CounterUpdated += UpdateCounterText;
}
private void MenuItemMedium_Click(object sender, RoutedEventArgs e)
{
lvl2.timer.Start();
}
private void UpdateCounterText(int newCounterValue)
{
TbTimer.Content = newCounterValue.ToString();
}
}
Incidentally, this ends up being similar to how the binding system is set up. If you just bound your textbox to the counter variable, it would be much cleaner and easier to use. To do that, you would change your XAML to:
<TextBox Name="TbTimer" Text="{Binding Counter}"/>
and assign the DataContext:
public class MainWindow
{
public MainWindow()
{
InitializeComponent();
lvl2 = new Level2();
DataContext = lvl2;
}
private void MenuItemMedium_Click(object sender, RoutedEventArgs e)
{
lvl2.timer.Start();
}
}
Level2 now needs to implement INotifyPropertyChanged, and you have to make counter a property (so it can be bound to):
class Level2 : INotifyPropertyChanged
{
//Notify Property Changed Implementation from MSDN:
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private int counter = 0;
public int Counter
{
get { return counter; }
set
{
counter = value;
NotifyPropertyChanged();
}
}
...
public void timer_Tick(object sender, EventArgs e)
{
Counter++;
}
}
The binding system will now update the text box automatically when the timer ticks (and increments the Counter property. This is the way it should be done in WPF, so feel free to ask any questions that come up when implementing it.
For reference, this is the implemenation of INofityPropertyChanged I used: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

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
}

Delegate doesn't notify the method

Would you look at my code and tell me where I went wrong? in following code I am trying to send a notification to myMethod() method when Form1 gets maximized.
Thanks!
namespace WindowsDelegate1
{
public delegate void ChangedEventHandler(object sender, EventArgs e);
class myForm : Form
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this,e);
}
public override System.Drawing.Size MaximumSize
{
//get
//{
// return base.MaximumSize;
//}
set
{
base.MaximumSize = value;
OnChanged(EventArgs.Empty);
}
}
}
}
namespace WindowsDelegate1
{
class EventListener
{
private myForm TheForm;
public EventListener(myForm theform)
{
TheForm = theform;
TheForm.Changed += new ChangedEventHandler(myMethod);
}
private void myMethod(object sender, EventArgs e)
{
MessageBox.Show("hey, window should be maximized now!");
}
public void Detach()
{
TheForm.Changed -= new ChangedEventHandler(myMethod);
TheForm = null;
}
}
}
Here is the testing unit / or main()
namespace WindowsDelegate1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
myForm f = new myForm();
EventListener listener = new EventListener(f);
f.ShowDialog();
f.WindowState = FormWindowState.Maximized;
listener.Detach();
}
}
}
What's probably happening is the event is either fired after your .Detach() call, or is never fired at all. I would start by removing the listener.Detach() call. Generally, you attach to events when the form is created or when it loads and detach when it is unloading.
Other than that, your Detach method is problematic because it tries to remove a different ChangedEventHandler instance than the one added. If you're wrapping your methods in ChangedEventHandler you need to store the instance you added.
Thank you for sharing your ideas!
I fixed it by removing the property (not idea why I used that!!) and using method instead by:
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
OnChanged(EventArgs.Empty);
}
I have updated my source code above too

How to subscribe to other class' events in C#?

A simple scenario: a custom class that raises an event. I wish to consume this event inside a form and react to it.
How do I do that?
Note that the form and custom class are separate classes.
public class EventThrower
{
public delegate void EventHandler(object sender, EventArgs args) ;
public event EventHandler ThrowEvent = delegate{};
public void SomethingHappened() => ThrowEvent(this, new EventArgs());
}
public class EventSubscriber
{
private EventThrower _Thrower;
public EventSubscriber()
{
_Thrower = new EventThrower();
// using lambda expression..could use method like other answers on here
_Thrower.ThrowEvent += (sender, args) => { DoSomething(); };
}
private void DoSomething()
{
// Handle event.....
}
}
Inside your form:
private void SubscribeToEvent(OtherClass theInstance) => theInstance.SomeEvent += this.MyEventHandler;
private void MyEventHandler(object sender, EventArgs args)
{
// Do something on the event
}
You just subscribe to the event on the other class the same way you would to an event in your form. The three important things to remember:
You need to make sure your method (event handler) has the appropriate declaration to match up with the delegate type of the event on the other class.
The event on the other class needs to be visible to you (ie: public or internal).
Subscribe on a valid instance of the class, not the class itself.
Assuming your event is handled by EventHandler, this code works:
protected void Page_Load(object sender, EventArgs e)
{
var myObj = new MyClass();
myObj.MyEvent += new EventHandler(this.HandleCustomEvent);
}
private void HandleCustomEvent(object sender, EventArgs e)
{
// handle the event
}
If your "custom event" requires some other signature to handle, you'll need to use that one instead.

Categories

Resources