NumericUpDown differentiate up and down - c#

I have a WinForm with some numreicUpDown Controls, i want to know if the value has been incremented or decremented. the control fires the event value changed for both situations, and as far as i can understand the programm calls the methods UpButton and DownButton. Is there any other way to know how the value has been changed or do i have to do this with this methods(like firing eventor implementig my code in Up-Down-Button)

There is no standart way to do this.
I sugest to remember the old value and compare it with new one
decimal oldValue;
private void ValueChanged(object sender, EventArgs e)
{
if (numericUpDown.Value > oldValue)
{
}
else
{
}
oldValue = numericUpDown.Value;
}

Create your own control that overrides those UpButton and DownButton methods:
using System.Windows.Forms;
public class EnhancedNUD : NumericUpDown
{
public event EventHandler BeforeUpButtoning;
public event EventHandler BeforeDownButtoning;
public event EventHandler AfterUpButtoning;
public event EventHandler AfterDownButtoning;
public override void UpButton()
{
if (BeforeUpButtoning != null) BeforeUpButtoning.Invoke(this, new EventArgs());
//Do what you want here...
//Or comment out the line below and do your own thing
base.UpButton();
if (AfterUpButtoning != null) AfterUpButtoning.Invoke(this, new EventArgs());
}
public override void DownButton()
{
if (BeforeDownButtoning != null) BeforeDownButtoning.Invoke(this, new EventArgs());
//Do what you want here...
//Or comment out the line below and do your own thing
base.DownButton();
if (AfterDownButtoning != null) AfterDownButtoning.Invoke(this, new EventArgs());
}
}
Then when you implement the control on your form, you can hook up some of the events to let you know which button was clicked or key (up/down) hit.

Related

How to implement an event class

This question is in reference to another question, mine is similar but I am asking for help beyond what I have read in this answer:
Raise an event whenever a property's value changed?
EDIT: What I am trying to accomplish is a global message "service" within the application such that I can write to the message variable from different places within the application and have the User Interface (winform) pick up on the fact that there was some change to that variable and based upon the event, I can read the message variable and display its content to the user. I hope this makes more sense now.
First, I am new to the world of C# and while I understand the code written as the most accepted answer, where I fail, is to understand the final implementation. If I place this code in a .cs file and I use the namespace in winform file how do I finalize the implementation? In my case, I would want to implement the class in the winform file so I can watch for an event to occur. Once the event occurred I would write some information to the user via the winform interface. I think I would need to use the "get" of the string...but not sure how the implementation would go? I apologize in advance if this doesn't make sense, I am trying to piece this all together. Thanks for any help on this!
For reference, I have start with the answer provide and altered it for my purposes:
public class Messaging : INotifyPropertyChanged
{
private string dLMessage;
protected void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(this, e);
}
protected void OnPropertyChanged(string propertyName)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
public string DLMessage
{
get { return dLMessage; }
set
{
if (value != dLMessage)
{
dLMessage = value;
OnPropertyChanged("DLMessage");
OnDLMessageChanged(EventArgs.Empty);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnDLMessageChanged(EventArgs e)
{
EventHandler handler = DLMessageChanged;
if (handler != null)
handler(this, e);
}
public event EventHandler DLMessageChanged;
}
Edit
According to your edited question, there are many different ways. One of those is making DLMesaage property and its change event static:
public class Messaging
{
private static string dLMessage;
public static string DLMessage
{
get { return dLMessage; }
set
{
if (value != dLMessage)
{
dLMessage = value;
OnDLMessageChanged(EventArgs.Empty);
}
}
}
protected static void OnDLMessageChanged(EventArgs e)
{
EventHandler handler = DLMessageChanged;
if (handler != null)
handler(null, e);
}
public static event EventHandler DLMessageChanged;
}
and then subscribe for event this way in all your different forms (for example in form load event)
Messaging.DLMessageChanged += msg_DLMessageChanged;
having this function in that form:
void msg_DLMessageChanged(object sender, EventArgs e)
{
MessageBox.Show("at last changed!");
}
You can unsubscribe for event this way:
Messaging.DLMessageChanged -= msg_DLMessageChanged;
For example if you subscribed for event in some forms, you can put unsubscribe code in Dispose override:
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
Messaging.DLMessageChanged -= msg_DLMessageChanged;
components.Dispose();
}
base.Dispose(disposing);
}
This way if you close the form, the event never be handled in that form.
Please note that I am keeping things simple in order to get your job done with minimum changes.
Original
Put this some where you instantiate Messageing instance for example in your form's constructor or load event handler:
Messaging msg = new Messaging();
msg.DLMessageChanged += msg_DLMessageChanged;
Add this to the form:
void msg_DLMessageChanged(object sender, EventArgs e)
{
MessageBox.Show("at last changed!");
//You can access the new value using Messaging.DLMessage
}
And also it seems you don't need to implement INotifyPropertyChanged if you only want DLMessageChanged. Now you are raising both events.
Or in case you want to use PropertyChanged event, put this some where you instantiate Messageing instance for example in your form's constructor or load event handler:
Messaging msg = new Messaging();
msg.PropertyChanged+= msg_PropertyChanged;
Add this to the form:
void msg_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "DLMessage")
MessageBox.Show("at last changed!");
}

Getting update from UserControl

Can someone tell me how can I have a feature in my UserControl, that can let the host windowsform know what is the control is doing?
For example my usercontrol has a filebrowser, and if user uses this file browser to open a file I want in the statusstrip bar of my form to write "Loading file(s)".
Will this require using events? if so, how can I have a single event inside usercontrol to report anything it does (then I guess I have to call this event in all methods in the usercontrol).
Simple
Yes, expose an event on the user control that the Form can subscribe to. You should use the standard event pattern:
class MyUserControl : UserControl
{
public event EventHandler<EventArgs> FileOpened;
protected virtual void OnFileOpened(EventArgs e)
{
EventHandler<EventArgs> handler = FileOpened;
if (handler != null)
handler(this, e);
}
}
Then when the file is opened you call OnFileOpened(EventArgs.Empty) which fires the event.
With custom EventArgs
Now the Form probably needs to know what file was opened. You could expose a property on the user control that the Form can use to find out, or you can provide that information in your event like so:
public class FileOpenedEventArgs : EventArgs
{
private string filename;
public FileOpenedEventArgs(string filename)
{
this.filename = filename;
}
public string Filename { get { return filename; } }
}
class MyUserControl : UserControl
{
public event EventHandler<FileOpenedEventArgs> FileOpened;
protected virtual void OnFileOpened(FileOpenedEventArgs e)
{
EventHandler<FileOpenedEventArgs> handler = FileOpened;
if (handler != null)
handler(this, e);
}
}
Then you fire the event with OnFileOpened(new FileOpenedEventArgs(filename)).
Optimal
When you create an event handler public event delegate Name;, you are allocating storage for the delegate on your object. Objects (especially Controls) often have a huge number of events that are never subscribed to. That's a whole lot of allocated storage not being used. There's an optimization built into the framework in the form of a EventHandlerList. This handy object stores event handlers only when they are actually used. All System.Windows.Forms.Control objects derive from System.ComponentModel.Component and it already provides an (protected) EventHandlerList that you can access in your derived Control.
To use it, you first create a static object that uniquely identifies your event, and then you provide the add {} and remove {} methods manually. Like so:
class MyUserControl : UserControl
{
private static readonly object FileOpenedKey = new Object();
public event EventHandler<FileOpenedEventArgs> FileOpened
{
add { Events.AddHandler(FileOpenedKey, value); }
remove { Events.RemoveHandler(FileOpenedKey, value); }
}
protected virtual void OnFileOpened(FileOpenedEventArgs e)
{
var handler = (EventHandler<FileOpenedEventArgs>)Events[FileOpenedKey];
if (handler != null)
handler(this, e);
}
}
Yes, you will need to create an event and subscribe to it. One suggestion following the standard pattern for events:
enum ControlStatus {Idle, LoadingFile, ...}
class StatusChangedEventArgs : EventArgs
{
public ControlStatus Status {get; private set;}
public StatusChangedEventArgs(ControlStatus status)
: base()
{
this.Status = status;
}
}
partial class MyControl : UserControl
{
public ControlStatus Status {get; private set;}
public event EventHandler<StatusChangedEventArgs> StatusChanged;
protected virtual void OnStatusChanged(StatusChangedEventArgs e)
{
var hand = StatusChanged;
if(hand != null) hand(this, e);
}
void LoadFiles()
{
...
Status = ControlStatus.LoadingFiles;
OnStatusChanged(new StatusChangedEventArgs(this.Status));
...
Status = ControlStatus.Idle;
OnStatusChanged(new StatusChangedEventArgs(this.Status));
}
}
partial class MyHostWindowsForm : Form
{
public MyHostWindowsForm()
{
var ctl = new MyControl();
...
ctl.StatusChanged += ctl_StatusChanged;
}
void ctl_StatusChanged(object sender, StatusChangedEventArgs e)
{
switch(e.Status)
{
case ControlStatus.Idle:
statusStripBar.Text = null;
break;
case ControlStatus.LoadingFiles:
statusStripBar.Text = "Loading file(s)";
break;
...
}
}
}

Creating an event in a dll and handling the event in a Form

I have created a DLL using the following code. I have compiled this code as a DLL.
namespace DllEventTrigger
{
public class Trigger
{
public delegate void AlertEventHandler(Object sender, AlertEventArgs e);
public Trigger()
{
}
public void isRinging()
{
AlertEventArgs alertEventArgs = new AlertEventArgs();
alertEventArgs.uuiData = "Hello Damn World!!!";
CallAlert(new object(), alertEventArgs);
}
public event AlertEventHandler CallAlert;
}
public class AlertEventArgs : EventArgs
{
#region AlertEventArgs Properties
private string _uui = null;
#endregion
#region Get/Set Properties
public string uuiData
{
get { return _uui; }
set { _uui = value; }
}
#endregion
}
}
Now I'm trying to handle the event triggered by this dll in a forms application with this code.
namespace DLLTriggerReciever
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Trigger trigger = new Trigger();
trigger.isRinging();
trigger.CallAlert += new Trigger.AlertEventHandler(trigger_CallAlert);
}
void trigger_CallAlert(object sender, AlertEventArgs e)
{
label1.Text = e.uuiData;
}
}
}
My problem i'm not sure where i went wrong. Please suggest.
You need to assign your event handler before the event is actually fired, otherwise the code will throw a NullReferenceException.
trigger.CallAlert += new Trigger.AlertEventHandler(trigger_CallAlert);
trigger.isRinging();
Additionally, it's a recommended practice to check first, whether there are handlers assigned:
var handler = CallAlert; // local variable prevents a race condition to occur
if (handler != null)
{
handler(this, alertEventArgs);
}
as #Gene said, you need to register the event before raising it.
anyway, it's a good practice to check if someone is register to the event you're about to raise by checking for null.
like this:
if (this.CallAlert != null)
this.CallAlert(new object(), alertEventArgs);

How to make own event handler?

I am making a windows forms project in C#, in which I made a class LabelX which inherits System.Windows.Forms.Label, then added a property Mass of float type
Now, my question is how can I handle, when value of Mass is changed.
e.g.:
When user enter value zero or less than zero
I want to fire a message that "Mass can't be zero or negative"
If I am interpreting this correctly, there are two parts to this. First, you need to detect invalid values and throw exceptions. Second, you need to raise an event when the property changes. This can be achieved as follows.
private float mass;
public float Mass
{
get
{
return this.mass;
}
set
{
if (value <= 0.0F)
{
throw new ArgumentOutOfRangeException("Mass cannot be zero or negative.");
}
if (this.mass != value)
{
this.mass = value;
OnMassChanged(EventArgs.Empty);
}
}
}
public event EventHandler MassChanged;
protected virtual void OnMassChanged(EventArgs args)
{
var handler = this.MassChanged;
if (handler != null)
{
handler(this, args);
}
}
To show a message if an invalid entry is made, you should put a try \ catch block around the call to set Mass and catch the ArgumentOutOfRangeException.
Try the following:
// Created an empty form with a LabelX control on it.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Added this event from the property manager.
private void labelX1_MassChanged(object sender, EventArgs e)
{
var label = (LabelX)sender;
if (label.Mass <= 0.0)
MessageBox.Show("Mass is less than or equal to 0");
}
}
public class LabelX : Label
{
private float _mass;
public float Mass
{
get { return _mass; }
set
{
if (!value.Equals(_mass))
{
_mass = value;
OnMassChanged(EventArgs.Empty);
}
}
}
public event EventHandler MassChanged;
protected virtual void OnMassChanged(EventArgs e)
{
if (MassChanged != null)
MassChanged(this, e);
}
}
Outside of your LabelX class, create the following class:
public class MassChangedEventArgs : EventArgs
{
public float Mass { get; private set; }
public MassChangedEventArgs(float mass)
{
this.Mass = mass;
}
}
Also outside of your LabelX class, create the following delegate. This will be your event handler.
public delegate void MassChangedEventHandler(object sender, MassChangedEventArgs e);
Within your LabelX class, create an event to broadcast:
public class LabelX
{
public event MassChangedEventHandler MassChanged;
//the rest of your code here...
}
You'll also want to create a private instance method that will fire your event.
public class LabelX
{
public event MassChangedEventHandler MassChanged;
private void OnMassChanged()
{
if(MassChanged!=null)
this.MassChanged(this, new MassChangedEventArgs(this.Mass));
}
//the rest of your code here...
}
Finally, whenever your Mass property changes, call OnMassChanged. For instance:
public class LabelX
{
private float mass;
public float Mass
{
get
{
return mass;
}
set
{
mass = value;
OnMassChanged();
}
}
public event MassChangedEventHandler MassChanged;
private void OnMassChanged()
{
if(MassChanged!=null)
this.MassChanged(this, new MassChangedEventArgs(this.Mass));
}
//the rest of your code here...
}
When you want to handle that event on a per-instance basis, you just have to register a listener with the MassChanged event of your underlying object and perform whatever actions are necessary.
Events are a common pattern used in the framework. The process typically involves defining a delegate to be used as the event handlers, declaring the event using the handler, defining methods to raise the event, then hooking up to the properties the logic to raise the event.
The message you describe is better done as an Exception but here's an example to define the MassChanged event.
// Define event args if you have additional
// information to pass to your event handlers
public class MassChangedEventArgs : EventArgs
{
public MassChangedEventArgs(int oldMass)
{
OldMass = oldMass;
}
public int OldMass { get; private set; }
}
public class SomeObject
{
// There's a generic event handler delegate that can be
// used so you only need to define the event arguments.
public event EventHandler<MassChangedEventArgs> MassChanged;
// Convenience method to raise the event
protected virtual void OnMassChanged(MassChangedEventArgs e)
{
if (MassChanged != null)
MassChanged(this, e);
}
public int Mass
{
get
{
return mass;
}
set
{
// Your checks here
if (value <= 0)
throw new ArgumentOutOfRangeException("Mass", "Mass can't be zero or negative");
// Should only raise the event if the new value is different
if (value != mass)
{
// Change the mass
MassChangedEventArgs e = new MassChangedEventArgs(mass);
mass = value;
// Raise the event
OnMassChanged(e);
}
}
}
private int mass;
}
After that, it's just a matter of registering handlers to the event and going from there.
I am quite sure you you would like to 'fire' an exception in your case.
This more of a validation logic issue such AOP code contracts concept.
But if you really like to create an event for it you have to at least:
1) create an event storage variable in your label class
public event EventHandler MassChanged;
2) in your property (note that you loose the ability to use code gen functions of c# 3 for
which 'auto' implement the field to store your Mass property value)
public bool Mass
{
get { return _mass; }
set {
// check if value is invalid (0 or less) && that event subscribers exist
if(value<=0 && MassChanged != null) { MassChanged(this, null); }
else // otherwise assign ...
{
_mass = value;
}
}
}
3) create an event handler of type EventHandler
Best to read the msdn article for events: link text
Again I am pretty sure you are not handling exceptions properly in the app
if you need an event for this. I mean there is nothing wrong but events are
usually not used as means of value validations.

Question about custom events

I'm making custom events for C# and sometimes it isn't working.
This is how I'm making the event happen:
private bool isDoorOpen;
public bool IsDoorOpen {
get { return isDoorOpen;}
private set { isDoorOpen = value; DoorsChangeState(this, null);}
}
And these are the event declarations:
//events
public delegate void ChangedEventHandler(Elevator sender, EventArgs e);
public event ChangedEventHandler PositionChanged;
public event ChangedEventHandler DirectionChanged;
public event ChangedEventHandler BreaksChangeState;
public event ChangedEventHandler DoorsChangeState;
This works as long as there are methods attached to the events, but if there isn't, it throws a null ref exception. What am I doing wrong?
The recommended way to call an event is
var handler = this.DoorsChangeState;
if (handler != null)
handler(this, null);
The reason for copying the handler locally is incase the event handler changes on another thread while you're checking for null.
EDIT: Found the article talking about race conditions.
http://blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx
I know this question has been discussed (and answered) several times here on SO.
Also somewhere here i got the following extension methods to make this pattern more easy to use:
public static class EventHandlerExtensions
{
public static void FireEvent<T>(this EventHandler<T> handler, object sender, T args) where T : EventArgs
{
var temp = handler;
if (temp != null)
{
temp(sender, args);
}
}
public static void FireEvent(this EventHandler handler, object sender)
{
var temp = handler;
if (temp != null)
{
temp(sender, EventArgs.Empty);
}
}
}
So in your code you can say:
public bool IsDoorOpen
{
get { return isDoorOpen;}
private set
{
isDoorOpen = value;
DoorsChangeState.FireEvent(this);
}
}
If a event isn't subscribed to when it fires, a NullReferenceException will be thrown. This is correct behaviour, not something you've done wrong.
You should check:
if(DoorsChangeState != null)
{
DoorsChangeState(this, null); // Only fire if subscribed to
}
Before invoking an event you must check if the event is null:
if (DoorsChangeState != null)
DoorsChangeState(this, null);
When DoorsChangeState is null that means there are no listeners on that event.
You need to check to see if the event has been subscribed to.
I use this standard form for throwing all of my events.
var temp = EventName;
if(EventName!= null)
temp(this, null);

Categories

Resources