I need a custom NumericUpDown where the event ValueChanged should pass CancelEventArgs instead of EventArgs as I want to be able to cancel the editing when certain conditions are verified (e.g. I have two NumericUpDown that must have always different values). If I try to override OnValueChanged I obviously get an error.
protected override void OnValueChanged(CancelEventArgs e)
{
if (e.Cancel)
return;
else
{
EventArgs args = (EventArgs)e;
base.OnValueChanged(args);
}
}
Is there a way to do this?
I would propose to change a little bit your implementation of the cancel behavior, instead of trying to pass the information of Cancellation through the event arguments, you can query it on demand by introducing a new event to your custom component. Here is a simple example:
class CustomNumericUpDown : NumericUpDown
{
protected override void OnValueChanged(EventArgs e)
{
if (QueryCancelValueChanging != null && QueryCancelValueChanging())
return;
else
{
EventArgs args = (EventArgs)e;
base.OnValueChanged(args);
}
}
public event Func<bool> QueryCancelValueChanging;
}
In this situation, the host of your component can subscribe to the new event in order to decide to cancel or not the "ValueChanged" event.
EDIT:
Usage example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
CustomNumericUpDown nudTest = new CustomNumericUpDown();
nudTest.QueryCancelValueChanging += NudTest_QueryCancelValueChanging;
}
private bool NudTest_QueryCancelValueChanging()
{
return true;/* Replace by custom condition here*/
}
}
Perhaps you need to learn how to create and manage custom events if you have never done it before, it should be easy to find tutorials on this topic on the web (like this one )
Related
I have DragDrop and DragEnter events on my SplitContainer.Panel:
splitContainer.Panel.DragDrop += new System.Windows.Forms.DragEventHandler(this.splitContainerPanelDragDrop);
splitContainer.Panel.DragEnter += new System.Windows.Forms.DragEventHandler(this.splitContainerPanelDragEnter);
It works perfect with every control inside SplitContainer.Panel except RichTextBox controls.
How it looks like:
So DragDrop/DragEnter works perfectly in every control inside SplitContainer except controls which is marked yellow color.
What I tried:
1) Set
RichTextBox.AllowDrop = false;
So I even DragEnter is unavailable with "action is not allowed" cursor.
2) Set
RichTextBox.AllowDrop = true;
After this cursor is ok, but it doesnt work because expects additional DragEventHandler in other case it doesnt work.
3) Set
RichTextBox.EnableAutoDragDrop=false;
RichTextBox.AllowDrop=true;
Same result as 2) variant.
I dont want to set DragDrop/DragEnter event for every RichTextBox inside SplitContainer because inside FlowLayoutPanel they are created dynamically.
The question is: is there any method like e.PreventDefault analog in C#? Or what can I do except setting events for every RichTextBox to make it work?
This worked for me
I created 2 custom controls
Custom SplitControl
public partial class SplitControlCustom : SplitContainer
{
public SplitControlCustom()
{
InitializeComponent();
}
public void ForceDrageDrop(DragEventArgs eventArgs)
{
OnDragDrop(eventArgs);
}
public void ForceDragEnter(DragEventArgs eventArgs)
{
OnDragEnter(eventArgs);
}
}
Custom RichTextBox
public partial class RichTextBoxCustom : RichTextBox
{
public RichTextBoxCustom()
{
InitializeComponent();
this.AllowDrop = true;
}
protected override void OnDragEnter(DragEventArgs drgevent)
{
SplitControlCustom parentSplitControl = Parent.Parent as SplitControlCustom;
if (parentSplitControl != null)
{
parentSplitControl.ForceDragEnter(drgevent);
}
}
protected override void OnDragDrop(DragEventArgs drgevent)
{
SplitControlCustom parentSplitControl = Parent.Parent as SplitControlCustom;
if (parentSplitControl != null)
{
parentSplitControl.ForceDrageDrop(drgevent);
}
}
}
Please let me know if it worked
I don't see how you can make this work directly. But then, since you are already willing to add a few lines of code while generating the controls, why not add the necessary events via a few lines of Lambda..:
Let's assume you have just created a RichTextBox and are ready to add it to some Controls collection..:
RichTextBox richTextBox = new RichTextBox ();
...
richTextBox.AllowDrop = true;
richTextBox.DragEnter += (ss, ee) => { ee.Effect = DragDropEffects.Copy; };
richTextBox.DragOver += (ss, ee) => { ee.Effect = DragDropEffects.Copy; };
richTextBox.DragDrop += (ss, ee)
=> { splitContainer.Panel_DragDrop(splitContainer.Panel, ee); };
The first two lambdas set the effect to copy without any checks; of course you will want to add those and pick the appropriate effect.
The third lambda passes the DragEventArgs on the the DragDrop event of the containing panel, so now the RTB is actually 'D&D-through' ..
Just create a custom RichTextBox and override it's DragDrop Events.
public class CustomRichTextBox : RichTextBox
{
#region Methods
#region Overrides
protected override void OnDragEnter(DragEventArgs e)
{
// base.OnDragEnter(e);
}
protected override void OnDragOver(DragEventArgs e)
{
// base.OnDragOver(e);
}
protected override void OnDragLeave(DragEventArgs e)
{
// base.OnDragLeave(e);
}
protected override void OnDrop(DragEventArgs e)
{
// base.OnDrop(e);
}
#endregion
#endregion
}
For some reason RichTextBoxes seem to handle all DragDrop events by default.
In WPF the events will propagate till it gets to the control that expects these events. I'm not sure about WinForms though.
This is what resolved this issue for me.
I had these two events defined, which should have been good enough
MyRichTextBox.DragEnter += MyRichTextBox_DragEnter;
MyRichTextBox.DragDrop += MyRichTextBox_DragDrop;
I found that this one is also apparently needed when using a RichTextBox embedded in
certain controls.
MyRichTextBox.DragOver += MyRichTextBox_DragOver;
private void MyRichTextBox_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
Please forgive my little knowledge!
I have the following class in HIDNewDeviceEventMonitor.cs:
public class HIDNewDeviceEventMonitor : IDisposable
{
// used for monitoring plugging and unplugging of USB devices.
private ManagementEventWatcher watcherAttach;
public HIDNewDeviceEventMonitor()
{
// Catch USB HID plugged instance event watching
watcherAttach = new ManagementEventWatcher();
watcherAttach.EventArrived += new EventArrivedEventHandler(watcher_EventArrived);
watcherAttach.Query = new WqlEventQuery(#"SELECT * FROM __InstanceCreationEvent WITHIN 2 WHERE TargetInstance ISA 'Win32_PNPEntity' AND TargetInstance.DeviceID LIKE 'HID\\VID_04D8%'");
watcherAttach.Start();
}
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
Debug.WriteLine("my device is inserted..");
}
public void Dispose()
{
watcherAttach.Stop();
watcherAttach.Dispose();
}
~HIDNewDeviceEventMonitor()
{
this.Dispose();
}
}
Now, how can I change this class to be able to add an event handler that the class can call from within watcher_EventArrived where someNewEvent is outside the class file, actually in the form.cs:
// code in the form
HIDNewDeviceEventMonitor ok = new HIDNewDeviceEventMonitor();
ok.Inserted += someNewEvent; // <-- my problem, I don't know how to add an event to the class this way
private void someNewEvent()
{
//Enumerate and add to listbox1
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
ok.Dispose();
}
I 've seen this thing with other classes, how can I make my class like that?
Your Inserted event should look like this:
public event EventHandler Inserted;
You invoke it like this:
private void OnInserted()
{
if (this.Inserted != null)
{
this.Inserted(this, EventArgs.Empty);
}
}
The signature for the event handler is this:
void someNewEvent(object sender, EventArgs e)
{
//
}
Then you should wrap that code in the constructor of the class:
HIDNewDeviceEventMonitor ok;
public ClassName()
{
ok = new HIDNewDeviceEventMonitor();
ok.Inserted += someNewEvent; // <-- my problem
}
Declare the ok variable outside the constructor, and instantiate it inside. Then add the event handler.
Pro tip: You could use the generic EventHandler<T> if you need to supply a custom implementation of e.
Simply put, you're trying to add events to your HIDNewDeviceMonitor class.
To do this, first you'll need to define a delegate.
public delegate void InsertedHandler;
Next, you'll need to define the event in your HIDNewDeviceMonitor class.
// Notice how the event uses the delegate that's been defined
// v
public event InsertedHandler Inserted;
Now you'll need something that "fires" the event, which could easily be put in your watcher_EventArrived method.
void watcher_EventArrived(object sender, EventArrivedEventArgs e)
{
Debug.WriteLine("my device is inserted..");
// Notice how we check the event handler for null.
// If you don't, it could throw a NullReferenceException.
// Irritating, but easy to debug.. Usually..
if (Inserted != null)
Inserted(); // Or whatever parameters you need.
}
We're all done with the HIDNewDeviceMonitor class.
Now whatever class that uses the HIDNewDeviceMonitor can use the EventHandler code that you provided.
However, it'll have to be the same delegate.
public class MyClass
{
HIDNewDeviceMonitor monitor;
public MyClass()
{
monitor = new HIDNewDeviceMonitor();
monitor.Inserted += DeviceInserted;
}
private void DeviceInserted()
{
// Execute code here
}
}
You need to do following in the HIDNewDeviceEventMonitor class:
1.) First define a public event inside the class like this-
public event EventHandler Inserted;
2.) Then fire this event within the code where you detect the changes in events. Like this-
if(Inserted != null)
Inserted(this,null);
The if condition checks if the event is registered by any listener. It's fired in case it is.
Hope this helps.
I have a custom checkbox control that inherited from System.Windows.Forms.Control
and it hasn't CheckedChanged event. I want to implement CheckedChange same as dot net native CheckBox. How can I do it well ?
You are inheriting fromn Control, not CheckBox, so the solution is similar to the one proposed by Frigik, but it's not exactly that one.
First of all you have to define the event in your class, i.e.:
public event EventHandler CheckedChanged;
In this way every developer using your control can subscribe/unsubscribe to the event. This is not enough, since the event will never be triggered. To do so, you have to define a method to trigger it, and the call this method whenever the state of your control changes:
private void RaiseCheckedChanged()
{
if (CheckedChanged!= null)
CheckedChanged(this, EventArgs.Empty);
}
Where this method will be called depends on the structure of your control. For instance if you have a property Checked, you could call the method in its setter:
public bool Checked
{
get { return _checked; }
set
{
_checked = value;
RaiseCheckedChanged();
}
}
Try this code :
CheckBox chkList1 = new CheckBox();
chkList1.CheckedChanged += new EventHandler(CheckBox_CheckedChanged);
protected void CheckBox_CheckedChanged(object sender, EventArgs e)
{
// Do your stuff
}
Try this:
public class YourCheckBox:CheckBox
{
public event EventHandler<EventArgs> OnCheckedChangedCustom;
protected override void OnCheckedChanged(EventArgs e)
{
if (OnCheckedChangedCustom!=null)
{
OnCheckedChangedCustom(this, EventArgs.Empty);
}
base.OnCheckedChanged(e);
}
}
The button which we can create on the form is written in terms of event handler in Form1.Designer.cs as
this.button1.Click += new System.EventHandler(this.button1_Click);
Here Click is public event EventHandler 's type and this EventHandler is a delegate as
public delegate void EventHandler(object sender, EventArgs e);
Now,
why can't it be '='(equals)
this.button1.Click = new System.EventHandler(this.button1_Click);
and also when I am passing the argument this.button1_Click, how does it match up to
void EventHandler(object sender, EventArgs e); delegate ? As here I have two arguments.
Please clear me with this.
Thank you
ttSo, let's see what event is.
Code, you are write
public event EventHandler MyEvent;
will compile to
private EventHandler MyEvent = null;
[MethodImp(MethodImplOptions.Synchronized)]
public void add_MyEvent(EventHandler value) {
MyEvent = (EventHandler)Delegate.Combine(MyEvent, value);
}
[MethodImp(MethodImplOptions.Synchronized)]
public void remove_MyEvent(EventHandler<NewMailEventArgs> value) {
MyEvent = (EventHandler)Delegate.Remove(MyEvent, value);
}
So, as you see, you cannot directly access to delegate and can only call += and -=, which is overridden for event class.
Also you can manually manage this mechanism by overriding methods += and -=.
You can do it like this:
public event EventHandler MyEvent
{
add { //your code for += here }
remove { //your code for -= here }
}
More about event and delegates you can read in book "CLR via C#". I found all of this in this book.
esentially, you are adding a handler to the event, not setting the one handler. you might want to have more handlers for an event. one handler should not preclude having other handlers because there might be multiple actions that you could want to take place in response to a single event that might happen in different classes and in different places and on different threads and under different conditions. += says make me a subscriber to this event (and potentially one subscriber among many).
What if you want to have multiple methods called on Click event. What you are doing with
this.button1.Click += new System.EventHandler(this.button1_Click);
is registering for this.button1_Click method to be invoked when Click event is raised. += adds handler and NOT assigns handler.
1/ it can not be '='(equals) because delegate is like a function pointer
2/ If you want to pass parameter to event button click, you have to make your own button class and implement Click event and have you own EventArgs
sample code:
public class MyEventArg
{
int _param1;
string _param2;
//you can add more param
public MyEventArg(int _param1,string _param2)
{
this._param1 = _param1;
this._param2 = _param2;
}
}
public delegate void MyButtonClickHandler(object sender, MyEventArg e)
public class MyButton:Control
{
public event MyButtonClickHandler OnMyClick;
//You can raise your event here
protected override void OnClick(EventArgs e)
{
MyEventArg e = new MyEventArg(1,"a");//just sample data here
this.OnMyClick(this,e);
}
}
In the form that contains MyButton class instant
public partial class Form1 : Form
{
MyButton myButton = new MyButton();
public Form1()
{
InitializeComponent();
myButton.OnMyClick += new MyButtonClickHandler(this.myButton_OnMyClicked);
}
private void myButton_OnMyClicked(object sender, MyEventArg e){
//your implementation
}
}
Dear Nagaraj Tantri,
For question 1: As said above, Due to Delegate can set up multi-event.
For question 2:As culithay said, if you want to pass custom arguments throug event buttion
click, if you want to use EventHandler and pass cutom own argument
you have to custom your control class and custom own event argument,
the custom event parameter CustomEventArg should inherit EventArg class.
You can take the sample code as below.
// Customs ColorChanged's event parameter.
public class ColorChangedEventArgs : EventArgs
{
private Color color;
public ColorChangedEventArgs(Color c)
{
color = c;
}
public Color GetColor
{
get { return color; }
}
}
//Add this method in your custom control
protected void ibtnTest_Click(object sender, ColorChangedEventArgs e)
{
//TODO;
}
You can also referen MSDN here
I've created a KeyPress event handler that prevents the entry of anything but digits, decimals, and backspace in any subscibing input control. The problem is that the handler is only available to the form within which it was created. Rather than copying the event handler to every form, is there a way to make it global - so that the keypress event of any input control on any form can subscribe to it.
Thank you.
Another more object oriented solution would be to inherit from the TextBox control and override the KeyPress event, creating your own custom type of TextBox.
class NumericTextBox : System.Windows.Forms.TextBox
{
protected override void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e)
{
base.OnKeyPress(e);
if (true /* insert your conditions */)
e.Handled = true;
}
}
Then use this control where needed in place of the regular TextBox control.
Make it public and static, and you should probably move it to a "Utilities" type class. (Or its own class)
namespace GlobalKeyPress
{
public class GlobalKeyPress
{
public static void KeyPressFilter(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if((e.KeyChar < '0' || e.KeyChar > '9') && e.KeyChar != '.')
e.Handled = true;
}
}
}
Delegates are normal objects, and as such, you can return them from methods.
Specifically, you'd want to create a KeyPressEventHandler delegate
public static class Utilities
{
private static KeyPressEventHandler handler = KeyPressed;
public static void KeyPressed(Object sender, KeyPressEventArgs e)
{
// Your logic here
}
public static KeyPressEventHandler getKeyPressHandler() {
return handler;
}
}
Note: I haven't tested this, though. It looks correct as per the pages on Using Delegates and KeyPressEventHandler