C# Event name is null - c#

I have a WinForms application wherein I have my main application with a separate class that is part of the solution. In the class which is defining a User control with Dev Express buttons, I have defined my event delegate, event, method and eventargs.
In the main program, i have defined my listener.
I am getting a null value in my event method and cannot see why. I have reviewed this a number of times and as far as I can see, it is completely correct.
I would appreciate any comments/corrections that would be useful here.
This is the code in my class.
public partial class XtraUserControl1 : XtraUserControl, IAnyControlEdit
{
public delegate void ButtonClickedEventHandler(object sender, ClickEventArgs e);
public event ButtonClickedEventHandler ButtonClicked;
public XtraUserControl1()
{
InitializeComponent();
}
public void OnButtonClicked(ClickEventArgs e)
{
if (ButtonClicked != null)
{
ButtonClicked(this, e);
}
}
public class ClickEventArgs : EventArgs
{
public readonly SimpleButton buttonClicked;
public ClickEventArgs(SimpleButton button)
{
this.buttonClicked = button;
}
}
This is the main code where I have defined the listener.
private void frmEHHeaders_Load(object sender, EventArgs e)
{
// Create the button group from the User Control XtraUserControl1 and add it to the grid repository
btnGroup = new User_Controls.XtraUserControl1();
RepositoryItemAnyControl riAny = new RepositoryItemAnyControl();
riAny.Control = btnGroup;
grdEHHeaders.RepositoryItems.Add(riAny);
colButtons.ColumnEdit = riAny;
// Add event handlers
this.grdEHHeaders.Views[0].MouseDown += gridView1_MouseDown;
gridView1.CustomRowCellEdit += GridView1_CustomRowCellEdit;
// Listener for the button class
btnGroup.ButtonClicked += new User_Controls.XtraUserControl1.ButtonClickedEventHandler(btnGroup_ButtonClicked);
GetData();
}
private void btnGroup_ButtonClicked(object sender, User_Controls.XtraUserControl1.ClickEventArgs e )
{
SimpleButton myButton = e.buttonClicked;
MessageBox.Show("You clicked " + myButton.Text);
}

Related

Passing more objects with eventhandler

I was reading similar questions about overloading eventhandlers by not using eventhandlers but delegates or by calling other functions from within the eventhandler. But I really can't see how I can bind the delegate to the custom control like I am binding ButtonClick in the code below. I have a form with let's say 10 custom controls. Each custom control has 5 buttons. The way I am passing the key presses from each button of each custom control is:
This is in my custom control's cs file (GlobalDebugMonitorControl.cs)
namespace GlobalDebugMonitor
{
public partial class GlobalDebugMonitorControl : UserControl
{
public GlobalDebugMonitorControl()
{
InitializeComponent();
}
public event EventHandler ButtonClick;
private void MultiControl_Click(object sender, EventArgs e)
{
if (this.ButtonClick != null)
this.ButtonClick(sender, e);//**How Do I put here both sender and this**
}
}
}
Then all the buttons in the custom control.designer.cs have something like this:
this.openFileBTN.Click += new System.EventHandler(this.MultiControl_Click);
this.editFilePathBTN.Click += new System.EventHandler(this.MultiControl_Click);
this.delControlBTN.Click += new System.EventHandler(this.MultiControl_Click);
this.addControlBTN.Click += new System.EventHandler(this.MultiControl_Click);
this.editCompanyNameBTN.Click += new System.EventHandler(this.MultiControl_Click);
And then in my form1
namespace GlobalDebugMonitor
{
public partial class Form1 : Form
{
protected void UserControl_ButtonClick(object sender, EventArgs e)
{
Button tempButton = (Button)sender;
GlobalDebugMonitorControl tempParentControl = (GlobalDebugMonitorControl)((tempButton.Parent).Parent).Parent;
}
private void Form1_Load(object sender, EventArgs e)
{
foreach (string item in tempGlobalPaths)
{
GlobalDebugMonitorControl tempGDMcontrol = new GlobalDebugMonitorControl();
tempGDMcontrol.Name = item.Split(',')[0];
tempGDMcontrol.companyNameLBL.Text = item.Split(',')[0];
tempGDMcontrol.globalPathTXT.Text = item.Split(',')[1];
tempGDMcontrol.ButtonClick += new EventHandler(UserControl_ButtonClick);
flowLayoutPanel1.Controls.Add(tempGDMcontrol);
}
}
}
}
As you can see I create a tempButton by the sender to do some things based on which button was pressed of the 5 and by sender.parent.parent (the custom control is inside a table that is inside a flowlayout that is inside another panel etc)I finally reach the custom control that tells me which of the 10 custom controls had it's button pressed.
So the question is, is there a way to pass both the sender(button that was pressed) and the great grandfather (the custom control that owns the sender button)? I mean it works but this way I need to now how many "generations" I need to go up.
Thank you for reading me.
You could introduce your own type of EventArgs
public class CustomEventArgs : EventArgs
{
public GlobalDebugMonitorControl Control { get; set; }
public CustomEventArgs(GlobalDebugMonitorControl control)
{
this.Control = control;
}
}
and then change eventHandler to use it:
public event EventHandler<CustomEventArgs> ButtonClick;
so the calling code would be:
this.ButtonClick(sender, new CustomEventArgs(this));
and of course the implementer of the event:
protected void UserControl_ButtonClick(object sender, CustomEventArgs e)
{
Button tempButton = (Button)sender;
GlobalDebugMonitorControl tempParentControl = e.Control;
}

checkbox.Checked dosent update on other forms

I have 2 forms, UserInterface and Client I'm passing checkbox2.Checked info to Client but it only works however it was at launch. When I tick or untick and close and reopenClient it wont notice the change.
Modifiers is Public on checkbox2 at UserInterface form.
Here is Client code:
public partial class Client : Form
{
private UserInterface ui1;
public Client()
{
InitializeComponent();
}
public void CheckBoxCheck()
{
if (ui1.checkBox2.Checked == true)
{
MessageBox.Show("true");
}
else
{
MessageBox.Show("false");
}
}
}
If the checkbox is ticked at launch Client will show "true" but if I click it (untick) and run Client it will still show "true".
What do I need to add or modify so checkbox2 will be updated in realtime. Thank you.
Note: I'm pretty new with coding, explanations are appreciated.
I'll be building on noMad17's answer, you have to subscribe to your CheckBox event in your UserInterface form. But the change is that now we will send the CheckBox that was clicked in the event. So this code is for your UserInterface form:
public event EventHandler SomeEvent;
protected void OnSomeEvent(object sender, EventArgs e)
{
EventHandler eh = SomeEvent;
if(eh != null)
{
eh(sender, e);
}
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
OnSomeEvent(sender, e);
}
Now for the Client, it needs to know what a UserInterface is so we have to pass UserInterface to the Client in the constructor, otherwise it won't initialize. Also here we are gonna work out the CheckBox event that the parent form is gonna give us. And in the end we have to unsubscribe the event. So this code is for your Client:
public partial class Client : Form
{
private UserInterface ui1;
public Client(UserInterface ui1)
{
InitializeComponent();
this.ui1 = ui1;
ui1.SomeEvent += UI1_SomeEvent;
}
private void UI1_SomeEvent(object sender, EventArgs e)
{
//Your code...
CheckBox c = sender as CheckBox;
if(c.Checked == true)
{
MessageBox.Show("true");
}
else
{
MessageBox.Show("false");
}
}
private void Client_FormClosing(object sender, FormClosingEventArgs e)
{
ui1.SomeEvent -= UI1_SomeEvent;
}
}
Your Forms should be connected. It looks like ui1 is a different instance of UserInterface form.
There are different approaches to pass the data between forms and it depends on your demands.
For instance you could create UserInterface form inside of Client. And use the Show() method to show it.
You should probably be making use of the Checkbox.Checked event inside UserInterface class and then fire a custom event that your Client can subscribe to.
public event EventHandler<EventArgs> CheckboxCheckedChanged;
protected void OnCheckboxCheckedChanged(EventArgs e)
{
if (CheckboxCheckedChanged != null)
CheckboxCheckedChanged(this, e);
}
private void checkbox2_CheckedChanged(object sender, EventArgs e)
{
OnCheckboxCheckedChanged(e);
}
And then in Client:
ui1.CheckboxCheckedChanged += ui1_CheckboxCheckedChanged;
private void ui1_CheckboxCheckedChanged(object sender, CheckBoxEventArgs e)
{
// Your code here
}

I am trying to raise event at UserControl, and catch it at Main program, But the event always return null

I am trying to raise a event in one of classes of userControl, and Fire it in the Main class. I tried two different ways to fire this event, one of them works, But I still want to know why other way cannot work, and how to fix it.
My userContol class:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
return;
}
Class1 c = new Class1();
Thread accept = new Thread(
() =>
{
c.connection();
}
);
accept.Start();
}
}
And the Class1:
public class Class1
{
public delegate void myhandler(object sender, EventArgs e);
public event myhandler test;
public Class1()
{
}
public void connection()
{
test(this, new EventArgs());
}
}
In the Main, I just simply add into referent, and add
xmlns:my="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
then I try to subscribe this event in the main
public partial class SurfaceWindow1 : SurfaceWindow
{
/// <summary>
/// Default constructor.
/// </summary>
public SurfaceWindow1()
{
InitializeComponent();
Class1 c = new Class1();
c.test+=new Class1.myhandler(c_test);
// Add handlers for window availability events
AddWindowAvailabilityHandlers();
}
public void c_test(object sender, EventArgs e)
{
MessageBox.Show("fire");
}
}
If I only raise this event not into thread, it works fine, but If I try to let it raise in this thread, this test event only return null, and shows:
Object reference not set to an instance of an object.
looks like I did not subscribe it ever. So How to fix it if I must use it in thread.
This is a good example of what you really shouldn't be doing. You are trying to subscribe to an event of a class that is "owned" by another class. You are basically digging through the type hierarchy to find the event you want. This goes against good design.
Especially in UI applications there is a design concept called Event Bubbling. The type that owns the original object raising the event handles that event. In the handling of that event, it raises its own duplicate event. Here is a short-ish program that shows the concept:
public class RootEventClass
{
public event EventHandler SomeKindOfEvent;
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
Console.WriteLine("Root Event Firing");
OnSomeKindOfEvent(this, EventArgs.Empty);
}
}
public class FirstOwnerClass
{
private RootEventClass _rootClass;
public event EventHandler SomeKindOfEvent;
public FirstOwnerClass()
{
_rootClass = new RootEventClass();
_rootClass.SomeKindOfEvent += _rootClass_SomeKindOfEvent;
}
void _rootClass_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("First Owner Class Handling Root Owner Event");
OnSomeKindOfEvent(this, e);
}
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
_rootClass.RaiseEvent();
}
}
public class SecondOwnerClass
{
private FirstOwnerClass _firstClass;
public event EventHandler SomeKindOfEvent;
public SecondOwnerClass()
{
_firstClass = new FirstOwnerClass();
_firstClass.SomeKindOfEvent +=_firstClass_SomeKindOfEvent;
}
void _firstClass_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("Second Owner Class Handling First Owner Event");
OnSomeKindOfEvent(this, e);
}
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
_firstClass.RaiseEvent();
}
}
public class Program
{
public static void Main(string[] args)
{
SecondOwnerClass secondOwner = new SecondOwnerClass();
secondOwner.SomeKindOfEvent += secondOwner_SomeKindOfEvent;
secondOwner.RaiseEvent();
Console.ReadKey(true);
}
static void secondOwner_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("Got an event from the second owner defined in main");
}
}
If you run this program, you will get the following output:
Root Event Firing
First Owner Class Handling Root Owner Event
Second Owner Class Handling First Owner Event
Got an event from the second owner defined in main
So what is happening here. The Main method defines a SecondOwner object and then tells it to raise an event, which just passes it up the ownership chain to the root object. The magic is the event bubbling. The event is intercepted by each owning class and passed on. This way it can decide to pass it on or not.
Also, the Main method only needs to know about the events created in the SecondOwner class, it doesn't have to dig through SecondOwner, FirstOwner and finally RootEventClass.
Its an easy concept to grasp really, don't force your users (or yourself) to dig through types and ownership to get to an event, if users of the class will need that event, duplicate the event and bubble it.

How can I pass addition parameters to my centralized event handlers?

In a WPF application, I've got my events centralized in one class like this:
public class EventFactory
{
public static void Button_Edit_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("you clicked edit");
}
public static void Button_Add_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("you clicked add");
}
}
so that I can reuse them in many Windows like this:
public Window1()
{
InitializeComponent();
ButtonEdit.Click += EventFactory.Button_Edit_Click;
ButtonAdd.Click += EventFactory.Button_Add_Click;
}
This works fine, but now I want the events to act on the Windows which call them which I was able to do when the event handlers were simply in the code-behind for each window.
How can I e.g. inject a window object into the event handler so that that event handler can directly manipulate it, something like this:
ButtonEdit.Click += EventFactory.Button_Edit_Click(this);
One way:
ButtonEdit.Click += EventFactory.ForConsumer<Window1>().Button_Edit_Click;
In other words, turn your factory class into an actual factory that creates objects based on some context. In this case, the context is the object consuming the events.
Another way:
public static void Button_Edit_Click(object sender, RoutedEventArgs e)
{
Window window = Window.GetWindow(sender as DependencyObject);
MessageBox.Show("you clicked edit");
}
I'm not particularly fond of either of these approaches, but there you go.
You can try something like this:
public class CommonEventHandler
{
private CommonEventHandler() { }
private object Context { get; set; }
public static EventHandler CreateShowHandlerFor(object context)
{
CommonEventHandler handler = new CommonEventHandler();
handler.Context = context;
return new EventHandler(handler.HandleGenericShow);
}
private void HandleGenericShow(object sender, EventArgs e)
{
Console.WriteLine(this.Context);
}
}
class Program
{
static void Main(string[] args)
{
EventHandler show5 = CommonEventHandler.CreateShowHandlerFor(5);
EventHandler show7 = CommonEventHandler.CreateShowHandlerFor(7);
show5(null, EventArgs.Empty);
Console.WriteLine("===");
show7(null, EventArgs.Empty);
}
}
You need to adapt the types to suit your needs but it shows the general idea.

Listening to Events in Main Form from Another Form in C#

I have an application that has a main form and uses an event handler to process incoming data and reflect the changes in various controls on the main form. This works fine.
I also have another form in the application. There can be multiple instances of this second form running at any given time.
What I'd like to do is have each instance of this second form listen to the event handler in the main form and update controls on its instance of the second form.
How would I do this?
Here's some sample code. I want to information from the_timer_Tick event handler to update each instance of SecondaryForm.
public partial class Form1 : Form
{
Timer the_timer = new Timer();
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
the_timer.Tick += new EventHandler(the_timer_Tick);
the_timer.Interval = 2000;
the_timer.Enabled = true;
}
void the_timer_Tick(object sender, EventArgs e)
{
// I would like code in here to update all instances of SecondaryForm
// that happen to be open now.
MessageBox.Show("Timer ticked");
}
private void stop_timer_button_Click(object sender, EventArgs e)
{
the_timer.Enabled = false;
}
private void start_form_button_Click(object sender, EventArgs e)
{
SecondaryForm new_form = new SecondaryForm();
new_form.Show();
}
}
class SecondForm
{
private FirstForm firstForm;
public SecondForm()
{
InitializeComponent();
// this means unregistering on form closing, uncomment if is necessary (anonymous delegate)
//this.Form_Closing += delegate { firstForm.SomeEvent -= SecondForm_SomeMethod; };
}
public SecondaryForm(FirstForm form) : this()
{
this.firstForm = form;
firstForm.Timer.Tick += new EventHandler(Timer_Tick);
}
// make it public in case of external event handlers registration
private void Timer_Tick(object sender, EventArgs e)
{
// now you can access firstForm or it's timer here
}
}
class FirstForm
{
public Timer Timer
{
get
{
return this.the_timerl
}
}
public FirstForm()
{
InitializeComponent();
}
private void Button_Click(object sender, EventArgs e)
{
new SecondForm(this).ShowDialog(); // in case of internal event handlers registration (in constructor)
// or
SecondForm secondForm = new SecondForm(this);
the_timer.Tick += new EventHandler(secondForm.Timer_tick); // that method must be public
}
Consider using loosely coupled events. This will allow you to couple the classes in such a way that they never have to be directly aware of each other. The Unity application block comes with an extension called EventBroker that makes this very simple.
Here's a little lick of the sugar:
public static class EVENTS
{
public const string UPDATE_TICKED = "event://Form1/Ticked";
}
public partial class Form1 : Form
{
[Publishes(EVENTS.UPDATE_TICKED)]
public event EventHandler Ticked;
void the_timer_Tick(object sender, EventArgs e)
{
// I would like code in here to update all instances of SecondaryForm
// that happen to be open now.
MessageBox.Show("Timer ticked");
OnTicked();
}
protected virtual void OnTicked()
{
if (Ticked == null) return;
Ticked(this, e);
}
}
public partial class SecondaryForm : Form
{
[SubscribesTo(EVENTS.UPDATE_TICKED)]
private void Form1_Ticked(object sender, EventHandler e)
{
// code to handle tick in SecondaryForm
}
}
Now if you construct both of these classes using Unity, they will automatically be wired together.
Update
Newer solutions use message bus to handle loosely coupled events. See http://masstransit-project.com/ or http://nimbusapi.github.io/ as examples.
I guess you can make SecondaryForm take in the parent form in the constructor, and the add an event handler in the constructor.
private void start_form_button_Click(object sender, EventArgs e)
{
SecondaryForm new_form = new SecondaryForm(this);
new_form.Show();
}
In SecondaryForm.cs:
public SecondaryForm(ISomeView parentView)
{
parentView.SomeEvent += .....
}

Categories