Best Practice with Common Event Handling - c#

In a WinForms solution, you have multiple controls of the same type. You need to add an event handler to each of the control and at the current time the event handler will be doing the same thing. You do not expect there to be difference between them down the road any reason.
eg:
ScheduledPatientsGrid.ProcessGridKey += ScheduledPatientsGrid_ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += RecentPatientsGrid_ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += RecentPatientsGrid_ProcessGridKey;
...
private void ScheduledPatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
...
}
private void RecentPatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
...
}
private void PatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
...
}
Now is it better to sharing an single Event Handler between the different events as shown below or use different ones like in the code sample shown above?
ScheduledPatientsGrid.ProcessGridKey += ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += ProcessGridKey;
private void ProcessGridKey(object sender, KeyEventArgs e)
{
...
}
In the following page, Microsoft seems to suggest that sharing is better, however I notice that they have not updated it since .NET 2.0 (ie: Visual Studio 2008)
http://msdn.microsoft.com/en-us/library/4ac48519%28v=vs.90%29.aspx
Is there a Guide that makes a best practices recommendation in this case?

I would absolutely use the same method. What possible benefit is there to having multiple methods which do exactly the same, none of which is named to say what it does?
Personally I abhor the source_EventName convention that Visual Studio spawns. I prefer to give my event handler methods meaningful names which say what they do. Then when you look down the event handler list in the designer, you can see that when a button is clicked, X will happen rather than "the button's click event handler will be called" which is useless.
Alternatively, use lambda expressions to subscribe to the events and call meaningful methods with meaningful parameters. (The sender and args are often useless for event handlers.)

In this case, I usually have them wrap a common method, but I keep their event handlers named per usage. This allows me to easily unit test the method and (usually) reduce the needed parameters, and any errors in the stack trace will be very readable as to which grid the process failed for:
ScheduledPatientsGrid.ProcessGridKey += ScheduledPatientsGrid_ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += RecentPatientsGrid_ProcessGridKey;
RecentPatientsGrid.ProcessGridKey += RecentPatientsGrid_ProcessGridKey;
...
private void ScheduledPatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
ProcessGridKey(e.Key);
}
private void RecentPatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
ProcessGridKey(e.Key);
}
private void PatientsGrid_ProcessGridKey(object sender, KeyEventArgs e)
{
ProcessGridKey(e.Key);
}
private void ProcessGridKey(Key e)
{
...
}
Your mileage may vary depending on what the shared method does, or the parameters passed in. (For example, in my above sample, I duplicate the pulling of the Key from the KeyEventArgs.

I prefer sharing, if the logic gets out of hand you can always just use the single event as a router to the correct method like...
private void ProcessGridKey(object sender, KeyEventArgs e)
{
if (sender is x)
xmethod();
if (sender is y)
ymethod(); //etc
}
I'm aware this syntax doesn't quite make sense as the sender will always be the same object in OP example, but you get the idea.

Related

Function handling across multiple datagridviews with minimal duplicate code

I have 10 datagridviews in a tabcontrol that require the same additional functions like copy/paste to be coded in. The code is fairly long to cover these and I'm trying to minimize the amount of duplicate code used.
My current method is to take the "object sender" from a form item event (such as KeyDown) and pass it to a single function handler method where it is cast to a "DataGridView" object. Then any cell selections and values can be modified using that DataGridView object.
Casting the "object" to a "DataGridView" seems crude. Will this cause any referencing issues down the road? Does this impose any odd limitations? Is there a more "widely used" programming practice to accomplish this task?
Function Handling
private void dgv01_KeyDown(object sender, KeyEventArgs e)
{
dgv_KeyDown_Handler(sender, e);
}
private void dgv02_KeyDown_1(object sender, KeyEventArgs e)
{
dgv_KeyDown_Handler(sender, e);
}
private void dgv03_KeyDown
....
private void dgv_KeyDown_Handler(object sender, KeyEventArgs e)
{
DataGridView dgvHandler = (DataGridView)sender;
// Handles ctrl+c/ctrl+v using dgvHandler to modify cell values
}

Calling methods with parameters inside other methods

I have this two methods that in the first look are fine.
But the problem is that e parameter of RadWizard2_NextButtonClick method is returning the value of e parameter of radTxb_TextChanged method.
I tried to change the name of e parameter in one of the methods but than returns me null all the time when in fact it should not.
Any idea why this is happening or where i am doing wrong??
protected void radTxb_TextChanged(object sender, EventArgs e)
{
//dothings
if (!opMsg.IsError)
{
RadWizard2_NextButtonClick(sender, e as WizardEventArgs); // arguments WITHOUT types
}
}
You have to create WizardEventArgs instance, e.g.:
protected void radTxb_TextChanged(object sender, EventArgs e) {
if (!opMsg.IsError) {
// It seems you have to provide some parameters:
// currentIndex and nextIndex which
RadWizard2_NextButtonClick(sender,
new WizardEventArgs(currentIndex, nextIndex));
}
}
If you inspect e instance, you'll find it of EventArgs type; and sice EventArgs has not been inherited from WizardEventArgs (quite the opposite is true: it is WizardEventArgs which is derived from EventArgs)
e as WizardEventArgs
returns null (e being EventArgs instabce can't be treated as WizardEventArgs instance)
I know i'm late to the party, however you might be able to just get away with null
protected void radTxb_TextChanged(object sender, EventArgs e)
{
//dothings
if (!opMsg.IsError)
{
RadWizard2_NextButtonClick(sender, null); // arguments WITHOUT types
}
}
Let me suggest a different approach.
You are trying to call a UI event handler directly. This is almost always a bad idea. Event handlers are designed to handle events, not to be used as library methods.
If you need the code from RadWizard2_NextButtonClick in your radTxb_TextChanged method, just extract it into a new method:
Before:
protected void RadWizard2_NextButtonClick(object sender, WizardEventArgs e)
{
... // some code here
}
After:
protected void RadWizard2_NextButtonClick(object sender, WizardEventArgs e)
{
DoStuff();
}
private void DoStuff()
{
... // some code here
}
You can now call DoStuff in your radTxb_TextChanged method.
When you need to do something, write a method that does exactly what you need. Give it a name that describes what it does, and give it only the arguments that it needs. Then you can call that method from event handlers or anywhere else. You can also put the method in a separate class so you can reuse it if needed across pages and keep the code-behind from getting too big.
It's peculiar that the built-in event handlers often contain vague arguments that aren't even used and aren't cast as the correct type, such as:
protected void radTxb_TextChanged(object sender, EventArgs e)
Obviously the sender isn't going to be any object. It's going to be a specific type of control. And the event args are also going to be of a particular type. The way they are cast implies that they don't matter, and in many cases they won't even be used. We know what happened just because the method fired, and we respond to that and ignore the arguments.
But we don't need to follow that convention. We can just write our methods according to their own requirements. If you want to do something with a RadWizard after an event has fired, you can just write the method you want:
public void DoSomethingWithTheRadWizard(RadWizard radWizard)
In the event handlers, extract whatever values you need from the arguments and then call your more specific method. It will be much easier to read and understand when all of the arguments are used and each is declared as the correct type.

Updating a field based on other fields being changed

If I have several fields containing a currency value and a total field, how do I keep the total up-to-date when any value is changed?
I know that I can use events like ActiveChanged or Changed against individual controls but this becomes laborious when you have a lot of fields and also creates a lot of identical methods which seems inefficient to me.
I know that I can also use a button but this requires more input from the user. I'd like it to be somewhat automated so that the total can be observed as values are entered, or at least when switching to the next field.
Currently it's going to be a lot of code like below.
private void field1_Changed(object sender, System.EventArgs e)
{
calculate();
}
private void field2_Changed(object sender, System.EventArgs e)
{
calculate();
}
If exactly same code needs to be executed then you can create only one event handler and point all them to same event handler
Go to form.designer.cs and change event handlers. For very basic example, 2 text box pointing to same event handlers
this.textBox1.TextChanged += new System.EventHandler(this.ValueChanged);
this.textBox2.TextChanged += new System.EventHandler(this.ValueChanged);
In form.cs
private void ValueChanged(object sender, EventArgs e)
{
this.label1.Text = (int.Parse(this.textBox2.Text)
+ int.Parse(this.textBox1.Text))
.ToString();
}

How to call treeView.SelectedItemChanged programmatically

In my program I would like to call to a SelectedItemChanged event using c# code-behind, I am just unsure about what to pass as parameters. This is for a TreeViewItem.
//Gets selected item in TreeView
private void TreeOne_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
MainWindowViewModel.SelectedItem = e.NewValue as TreeViewItem;
}
//I'm calling the SelectedItemChanged event from a RightButtonDown event
private void TreeOne_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
TreeOne_SelectedItemChanged(/* What would go here? **/);
}
Also, when I try to build this I receive this compiler error that pretty much led to this question...
No overload for method TreeOne_SelectedItemChanged takes '0' arguments
I'm hoping that this is an easy question, but if I have not provided enough information, or haven't been clear enough please let me know.
Adding to #Bart Friederichs' answer and assuming that you have a reference to your TreeView, you could add the following method:
private void SetSelectedItem()
{
MainWindowViewModel.SelectedItem = TreeOne.SelectedItem;
}
Then you can simply call this from wherever you like:
private void TreeOne_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
SetSelectedItem();
}
private void TreeOne_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
SetSelectedItem();
}
The usual design pattern would be to call some kind of processing method, and not to "manually" fire events:
private TreeOne_SelectedItemChaned(object sender,
RoutedPropertyChangedEventArgs<object> e) {
processChange();
}
Then, from withing your code, you just call processChange(), no need to call TreeOne_SelectedItemChanged.
try to call
TreeOne_SelectedItemChanged(null, null);

Trigger control's event programmatically

Assume that I have a WinFoms project. There is just one button (e.g. button1).
The question is: is it possible to trigger the ButtonClicked event via code without really clicking it?
Button controls have a PerformClick() method that you can call.
button1.PerformClick();
The .NET framework uses a pattern where for every event X there is a method protected void OnX(EventArgs e) {} that raises event X. See this Msdn article. To raise an event from outside the declaring class you will have to derive the class and add a public wrapper method. In the case of Button it would look like this:
class MyButton : System.Windows.Forms.Button
{
public void ProgrammaticClick(EventArgs e)
{
base.OnClick(e);
}
}
You can just call the event handler function directly and specify null for the sender and EventArgs.Empty for the arguments.
void ButtonClicked(object sender, EventArgs e)
{
// do stuff
}
// Somewhere else in your code:
button1.Click += new EventHandler(ButtonClicked);
// call the event handler directly:
ButtonClicked(button1, EventArgs.Empty);
Or, rather, you'd move the logic out of the ButtonClicked event into its own function, and then your event handler and the other code you have would in turn call the new function.
void StuffThatHappensOnButtonClick()
{
// do stuff
}
void ButtonClicked(object sender, EventArgs e)
{
StuffThatHappensOnButtonClick();
}
// Somewhere else in your code:
button1.Click += new EventHandler(ButtonClicked);
// Simulate the button click:
StuffThatHappensOnButtonClick();
The latter method has the advantage of letting you separate your business and UI logic. You really should never have any business logic in your control event handlers.
Yes, just call the method the way you would call any other. For example:
private void btnSayHello_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello World!");
}
private void btnTriggerHello_Click(object sender, EventArgs e)
{
btnSayHello_Click(null, null);
}
button1.PerformClick();
But if you have to do something like this maybe it's better to move the code you have under the event on a new method ?
Why don't you just put your event code into a Method. Then have the Event execute the method. This way if you need to execute the same code that the Event rises, you can, but simply just calling the "Method".
void Event_Method()
{
//Put Event code here.
MessageBox.Show("Hello!");
}
void _btnSend_Click(object sender, EventArgs e)
{
Event_Method();
}
void AnotherMethod()
{
Event_Method();
}
Make sense? Now the "Click" event AND anywhere in code you can trigger the same code as the "Click" event.
Don't trigger the event, call the method that the event calls. ;)
In most cases you would not need to do that. Simply wrap your functionality in functions related to a specific purpose (task). You call this function inside your event and anywhere else it's needed.
Overthink your approach.
I recently had this problem where I wanted to programatically click a button that had multiple event handlers assigned to it (think UserControl or derived classes).
For example:
myButton.Click += ButtonClicked1
myButton.Click += ButtonClicked2;
void ButtonClicked1(object sender, EventArgs e)
{
Console.WriteLine("ButtonClicked1");
}
void ButtonClicked2(object sender, EventArgs e)
{
Console.WriteLine("ButtonClicked1");
}
When you click the button, both functions will get called. In the instances where you want to programmatically fire an event handler for a function from a form (for example, when a user presses enter in a Text field then call the InvokeOnClick method passing through the control you. For example
this.InvokeOnClick(myButton, EventArgs.Empty);
Where this is the Form instance you are in.
use a for loop to call the button_click event
private void btnadd_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i <= 2; i++)
StuffThatHappensOnButtonClick();
}
void StuffThatHappensOnButtonClick()
{
........do stuff
}
we assume at least one time you need click the button

Categories