In my app I have a lot of copy and paste code that is exactly the same and performs exactly the same function (button click events and the like). These redundant code live in the code-behind of many of my pages. So I decided to reduce the code duplication and to move these methods into a class file and only make a call to them from the code-behind pages.
Here is an example of a button click event in my code behind calling the methods from a class file:
#region DELETE selected users - button
protected void btnDeleteSelected_Click(object sender, EventArgs e)
{
try
{
UserGvUtil.DeleteSelectedUsersAndProfiles(GridView1, Msg);
}
catch (Exception ex)
{
UserGvUtil.ExceptionErrorMessage(Msg, ex);
}
finally
{
UserGvUtil.RefreshGridView(GridView1);
}
}
#endregion
Can I combine this try/catch block into yet another method and move it to the same class file? So, the only thing I have in the click event is a single line of code.
Does it make sense to do this? Not sure why, but I would like to have my code behind files as clean and simple as possible so I can make all the edits in a single place.
Sorry if I make no sense. I'm just learning about classes and methods and it floods my head with lots of ideas.
You can move the stuff inside the try block into an anonymous delegate that you pass to a shared method that has a try/catch. You really don't need to put the refresh into the finally, though. In fact, I would think you would only want to run it if the try block succeeds.
You can wire the event handlers manually.
btnDeleteSelected1.Click += Events.BtnDeleteSelected_Click;
btnDeleteSelected2.Click += Events.BtnDeleteSelected_Click;
...
btnDeleteSelected3.Click += Events.BtnDeleteSelected_Click;
public static class Events
{
public static BtnDeleteSelected_Click(object sender, EventArgs e)
{
...
}
}
Edit (for downvoters: ???)
The code will give you a one liner and you won't have to worry about writing custom events when they are all the same.
Also, if the utility methods have the same signature you could have a generic method:
public void ExecuteGvMethod(Action<GridView, string> gvMethod, GridView gv, string msg)
{
try
{
gvMethod(gv, msg);
}
catch (Exception ex)
{
UserGvUtil.ExceptionErrorMessage(msg, ex);
}
finally
{
UserGvUtil.RefreshGridView(GridView1);
}
}
And in code:
public static class Events
{
public static BtnDeleteSelected_Click(object sender, EventArgs e)
{
ExecuteGvMethod(UserGvUtil.DeleteSelectedUsersAndProfiles, (GridView)sender, "hi of whatever");
}
}
I'm risking a downvote, but here are my 2 cents:
Instead of using a try/catch, use a method that returns a status code.
For instance (just an idea, instead of using enum you can use a more complex class):
public enum StatusCode
{
Success = 1,
Error =2
}
public class UserGvUtil
{
public StatusCode getStatusAfterDelete(GridView GridView1, string Msg)
{
try
{
DeleteSelectedUsersAndProfiles(GridView1, Msg);
Return StatusCode.Success;
}
catch (Exception ex)
{
UserGvUtil.ExceptionErrorMessage(Msg, ex);
Return StatusCode.Error;
}
}
//your other methods here
}
Then in code behind:
protected void btnDeleteSelected_Click(object sender, EventArgs e)
{
StatusCode sc = UserGvUtil.getStatusAfterDelete(GridView1, Msg);
//then do something with the status code if you have to:
if (sc==StatusCode.Error) throw new Exception("Error deleting users and profiles");
else UserGvUtil.RefreshGridView(GridView1);
}
That way you can change your try/catch later if you think it affects performance etc...
Hope it helps.
I have a lot of copy and paste code
that is exactly the same ... (button
click events and the like)
Just move all of that code that's duplicated behind multiple click handlers into a method in a separate class and pass whatever's needed (in this case the GridView and whatever that MSG object is) as parameters. If its saving significant duplication then it would make sense to do so. DRY (Don't Repeat Yourself) is a valid principle.
Related
This question deals with events (base class events and subclass events) and event handlers. I'm working on existing code, that doesn't seem to work the way the author expected it. I have difficulty understanding why it doesn't work though, so I want to understand what's going on before I try to fix the existing code.
I've found the following question, which may or may not suggest I need to make an additional event handler for the subtype events:
C#: Raising an inherited event
If making an additional event handler is indeed the solution, I would still like to learn why this is the case. This is my first question here, and I did really try to search for the answer/explanation to my question, but sincere apologies if it's still something I should've easily found. A stern "RTFM!" with a educational link would be fine with me at this point :)
We have 2 event classes, a base type and a subtype. The subtype event exists to deal with deletion events.
public class BaseTypeEvent
{
public Guid Id { get; set; }
public string Name { get; set; }
public BaseTypeEvent()
{ }
public BaseTypeEvent(SomeRandomThing item)
{
Id = item.Id;
Name = item.Name;
}
}
public class SubTypeEvent : BaseTypeEvent
{
public DateTimeOffset Deleted { get; set; }
public SubTypeEvent()
{
Deleted = DateTimeOffset.UtcNow;
}
}
A usage of these events that seems to be failing:
public class UsageClass
{
public UsageClass(IEventBusService eventBusService)
{
eventBusService.MyBaseTypeEvents += HandleMethod;
}
private void HandleMethod(BaseTypeEvent e)
{
if(e is SubTypeEvent)
{
//code that deals with deletion events
//execution never actually gets here
}
//code that deals with events that are not deletion events
}
}
The declaration of the events are in the IEventBusService and EventBusService:
public delegate void MyEventHandler(BaseTypeEvent e);
public interface IEventBusService
{
public event MyEventHandler MyBaseTypeEvents;
void PublishStuff(BaseTypeEvent e);
}
public class EventBusService : IEventBusService, IDisposable
{
public void Initialize()
{
//Bus is MassTransit
Bus.Initialize(sbc =>
{
sbc.Subscribe(subs => subs.Handler<BaseTypeEvent>(OnBaseTypeEvent));
}
}
private void OnBaseTypeEvent(BaseTypeEvent e)
{
if (MyBaseTypeEvents == null) return;
try
{
MyBaseTypeEvents(e);
}
catch (Exception e)
{
//some logging
}
}
public event MyEventHandler MyBaseTypeEvents;
public void PublishStuff(BaseTypeEvent e)
{
//some logging
//publish e to the event bus of our choice (MassTransit)
Bus.Instance.Publish(e);
}
}
And then finally the place where we send the deletion event (to try to delete an item of what I have cleverly named SomeRandomThing above):
eventBusService.PublishStuff(new SubTypeEvent
{
Id = id,
Deleted = DateTimeOffset.UtcNow
});
So the problem: after sending the deletion event with the last line of code above, the if-statement in the UsageClass that checks whether an incoming event is of type SubTypeEvent is never actually true. The type of e in HandleMethod of UsageClass is BaseTypeEvent.
Edit:
I've decided to get rid of the subtyping in this case. We now no longer have BaseTypeEvent and SubTypeEvent, but simply EventTypeA and EventTypeB. One deals with creates and updates, the other deals with deletes (for which we need significantly less information that the creates and updates anyway).
public delegate void MyEventAHandler(EventTypeA e);
public delegate void MyEventBHandler(EventTypeB e);
and
void PublishStuffForA(EventTypeA e);
void PublishStuffForB(EventTypeB e);
and so on.
I've made an extra subscription to MassTransit in the Initialize method of our EventbusService, and made extra handlers in the various UsageClasses that needed them:
sbc.Subscribe(subs => subs.Handler<EventTypeA>(OnEventTypeA));
sbc.Subscribe(subs => subs.Handler<EventTypeB>(OnEventTypeB));
and
public UsageClass(IEventBusService eventBusService)
{
eventBusService.MyEventTypeAEvents += HandleMethodForA;
eventBusService.MyEventTypeBEvents += HandleMethodForB;
}
and so on.
I now no longer have to check if an incoming event is of a certain type, I just handle to two types separately. Perhaps a cop out, but it works.
I'm hesitant to qualify this as the answer to my own question, as #Glubus' comments as well as #Travis' comments were what answered my question. Still thought this small edit write-up might be nice to let everyone know what I did as a solution :)
Edit 2:
Sources of information that were helpful:
Derived types are not published to consumers in MassTransit
MassTransit message mis-typing
MassTransit: Message contracts, polymorphism and dynamic proxy objects
https://groups.google.com/forum/#!searchin/masstransit-discuss/polymorphism/masstransit-discuss/q_M4erHQ7OI/FxaotfIzI7YJ
So I can tell you the short answer:
Using polymorphism in messaging contracts introduces coupling.
We believe, as MassTransit developers, that this is a bad idea. It's still possible, but not out of the box. You have to use binary serialization or a customer serializer. The default the serialization pipeline only populates a proxy of the type in the consumer.
Let's say that I am writing a class library of some sort. I have a class:
public class PopupControl : UserControl {
// Some code
public event EventHandler PopupFinished;
}
If I want to handle this event in another class, I just use the += operator and nothing special happens. However, when the event is not handled anywhere, PopupFinished is null. And when I call PopupFinished (this, EventArgs.Empty), I get a NullReferenceException. So I need to do this:
public PopupControl () {
PopupFinished += popupFinished;
//Some more code
}
private void popupFinished (object sender, EventArgs e) {}
This doesn't sound like a good programming practice though. (or is it?)
Then I thought of another way:
try {
PopupFinished (this, EventArgs.Empty);
} catch (NullReferenceException) {}
But that doesn't sound right either.
Please tell me which of the above is better and whether there is another way to do that. Thanks!
Do a test to check PopupFinished is not null before calling it.
if(PopupFinished != null)
PopupFinished();
I've reviewed the MSDN doc and a couple SO answers, and all signs point to this working. At this point, I think I've either completely misunderstood what to expect or I've missed one line of code I need.
In short, I've got a WinForms app with a button, and I want another function to "click" that button at one point in the code. Here's the relevant bits:
// form.Designer.cs
this.btnAddBranch.Click += new System.EventHandler(this.btn_add_Click);
// form.cs
// using statements
public partial class EditClient : Form
{
// ...
public TestClick()
{
//btnAddBranch.PerformClick(); <-- would like to know why this fails ...
btn_add_Click(this, EventArgs.Empty);
}
private void btn_add_Click(object sender, EventArgs e)
{
MessageBox.Show("You clicked it!");
}
}
The commented line for btnAddBranch.PerformClick() is what I was hoping would do the equivalent of the line below it. But it doesn't, it doesn't seem to do anything when TestClick() is called. If I do the uncommented line, it works fine.
Am I missing something, or am I totally misunderstanding something?
Your problem is that TestClick() is your form constructor. There are no Controls to call PerformClick() on until the Form Constructor is complete. If you really want to call the code that early then do something like the following.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//Do not call methods on controls here, the controls are not yet initialized
}
private void TestClick()
{
btn_add.PerformClick();
}
private void btn_add_Click(object sender, EventArgs e)
{
MessageBox.Show("You Clicked it");
}
private void Form1_Load(object sender, EventArgs e)
{
TestClick();
}
}
Calling your PerformClick() anywhere other than the form constructor will create the desired results.
Sorry, I've updated my answer to correct it. I initially thought it was because you were not calling Button.PerformClick() after Form.InitializeComponent() (from the Form.Designer.cs auto-generated code), but I was corrected that this still does not work.
It seems that the Form is not sufficiently created in the constructor to allow Button.PerformClick(). I theorized that this may due to the fact that the Modal message loop wasn't fully created yet, but after looking at Button.PerformClick's code in Reflector, that doesn't seem to be quite the case.
PerformClick's code looks like this:
public void PerformClick()
{
if (base.CanSelect)
{
bool flag;
bool flag2 = base.ValidateActiveControl(out flag);
if (!base.ValidationCancelled && (flag2 || flag))
{
base.ResetFlagsandPaint();
this.OnClick(EventArgs.Empty);
}
}
}
While looking through, the first failure I notice here is CanSelect will return false because the control is not currently Visible (ShowDialog has not yet been called). Therefore, PerformClick will do nothing as observed. This is by digging down through the CanSelect implementation:
internal virtual bool CanSelectCore()
{
if ((this.controlStyle & ControlStyles.Selectable) != ControlStyles.Selectable)
{
return false;
}
for (Control control = this; control != null; control = control.parent)
{
if (!control.Enabled || !control.Visible)
{
return false;
}
}
return true;
}
In the debugger, you can put a breakpoint in the constructor and see that Button1 will not yet be visible (makes sense).
However, I will suggest that you can accomplish what you want from the constructor, by separating your application logic from the Button's event handler. For example...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
DoSomething();
}
private void DoSomething()
{
// application logic here...
MessageBox.Show("Hello World");
}
private void button1_Click(object sender, EventArgs e)
{
DoSomething();
}
}
Or, as the previous answer suggests you can call Button.PerformClick() from the Form.OnLoad method. However, it is probably better to just call the application logic directly from both spots instead of performing button clicks in the UI.
Sorry for the initially incorrect answer. Hope this helps explain.
Make sure your form is already Shown :)
If its hidden, or not shown, you cant perform a click.
Atleast this way it worked for me (i show a form for a short moment, perform a click, and hide it immidiately after).
And it works!
I have this code:
public partial class FrmPrincipal : Form
{
private Image imagen;
public FrmPrincipal()
{
InitializeComponent();
...
}
private void menuItem1_Click(object sender, EventArgs e)
{
Thread t = new Thread(RequestImage);
t.Start();
}
private void RequestImage()
{
try
{
...
// I want to update this.token
this.imagen = retrieveImageFromWebService();
...
}
catch (Exception ex)
{
...
}
}
}
How can I update image? I want to save a copy of image to update a pictureBox when user needs it.
Thanks!
Your code will work perfectly well is it is. However, if you want to read the value from another thread and make sure you always get the most recent value, you should either make it volatile or acquire a lock each time you read or write it.
See the memory model section of my threading article for more information.
The code you have there should work fine. If you are using token in the other thread through, you'll probably want to syncronize gets and sets to avoid data corruption:
private string token {
[MethodImpl(MethodImplOptions.Synchronized)] get;
[MethodImpl(MethodImplOptions.Synchronized)] set;
}
This syncronization method is not 100% safe in all circumstances, but for your purposes it should work
Is it possible under any set of circumstances to be able to accomplish this?
My current circumstances are this:
public class CustomForm : Form
{
public class CustomGUIElement
{
...
public event MouseEventHandler Click;
// etc, and so forth.
...
}
private List<CustomGUIElement> _elements;
...
public void CustomForm_Click(object sender, MouseEventArgs e)
{
// we might want to call one of the _elements[n].Click in here
// but we can't because we aren't in the same class.
}
}
My first thought was to have a function similar to:
internal enum GUIElementHandlers { Click, ... }
internal void CustomGUIElement::CallHandler(GUIElementHandler h, object[] args) {
switch (h) {
case Click:
this.Click(this, (EventArgs)args[0]);
break;
... // etc and so forth
}
}
It's a horribly ugly kludge, but it should work... There must be a more elegant solution though? The .NET library does this all the time with message handlers and calling events in Control's. Does anyone else have any other/better ideas?
You just need to add a public method for invoking the event. Microsoft already does this for some events such as PerformClick for controls that expose a Click event.
public class CustomGUIElement
{
public void PerformClick()
{
OnClick(EventArgs.Empty);
}
protected virtual void OnClick(EventArgs e)
{
if (Click != null)
Click(this, e);
}
}
You would then do the following inside your example event handler...
public void CustomForm_Click(object sender, MouseEventArgs e)
{
_elements[0].PerformClick();
}
The event keyword in c# modifies the declaration of the delegate. It prevents direct assignment to the delegate (you can only use += and -= on an event), and it prevents invocation of the delegate from outside the class.
So you could alter your code to look like this:
public class CustomGUIElement
{
...
public MouseEventHandler Click;
// etc, and so forth.
...
}
Then you can invoke the event from outside the class like this.
myCustomGUIElement.Click(sender,args);
The drawback is that code using the class can overwrite any registered handlers very easily with code like this:
myCustomGUIElement.Click = null;
which is not allowed if the Click delegate is declared as an event.
You can shorten the code suggested in the accepted answer a lot using the modern syntax feature of the .NET framework:
public event Action<int> RecipeSelected;
public void RaiseRecpeSelected(int recipe) => RecipeSelected?.Invoke(recipe);
You really should wrap the code you want to be able to execute from the outside in a method. That method can then do whatever your event would do - and that event would also instead call that method.