How to call an EventHandler in a parent class - c#

I have added an EventHandler for the Click-event to a picturebox but on runtime this handler is never called (the debugger shows me that it is added to the control directly but when I click on the picturebox nothing happens).
I assume it has something to do with my inheritance. I have a usercontrol called AbstractPage (its not really abstract since the designer doesnt like that) which only consists of a heading and this picturebox but it provides quite some functions the actual pages rely on.
#region Constructor
public AbstractPage()
{
InitializeComponent();
lblHeading.Text = PageName;
picLock.Click += new EventHandler(picLock_Click);
}
#endregion
#region Events
void picLock_Click(object sender, EventArgs e)
{
...do some stuff
}
#endregion
The page implementations just inherit this class and add their controls and behavior. We recently figured out that subclassing UserControl is not performant and we lose some performance there, but its the best way to do it (I dont want to c&p function for 25 pages and maintain them).
My pageA looks like this
public partial class PageA : AbstractPage
{
#region Constructor
public PageA()
{
// I dont call the base explicitely since it is the
// standard constructor and this always calls the base
InitializeComponent();
}
#endregion
public override string PageName
{
get { return "A"; }
}
public override void BindData(BindingSource dataToBind)
{
...
}
Anyway, the picLock_Click is never called and I dont know why?
The pages are all put into a PageControl which consists of a TreeView and a TabContainer where the pages are put once I call addPage(IPage)
public partial class PageControl {
...
protected virtual void AddPages()
{
AddPage(new PageA());
AddPage(new PageD());
AddPage(new PageC());
...
}
protected void AddPage(IPage page)
{
put pagename to treeview and enable selection handling
add page to the tabcontainer
}
Thanks in advance

If I understand your problem correctly, this worked for me out of the box (using VS2k8). My code:
public partial class BaseUserControl : UserControl
{
public BaseUserControl()
{
InitializeComponent(); //event hooked here
}
private void showMsgBox_Click(object sender, EventArgs e)
{
MessageBox.Show("Button clicked");
}
}
public partial class TestUserControl : BaseUserControl
{
public TestUserControl()
{
InitializeComponent();
}
}
I moved the TestUserControl to a form, clicked the button and got the message box as expected. Can you paste some more code, e.g. how do you use your AbstractPage?

I found the problem. We are using the Infragistics WinForms but in that case I used the standard picturebox. I replaced it with the UltraPictureBox and now it works.

Related

switch usercontrols in mainform within a usercontrol click event

This may sound stupid, But I am having hard time to figure this out; any help would be appreciated:
I have two user controls called “Safety_Check” and “OEE_Track”. In my MainForm I have a panel called “pnl_main_controller” this is where I am displaying both my user controls. I have two buttons on my main form and I am dynamically switching between both without any issue.
Safety_Check User control;
public partial class Safety_Check : UserControl
{
private static Safety_Check _instance;
public static Safety_Check instance
{
get
{
if (_instance == null)
_instance = new Safety_Check();
return _instance;
}
}
public Safety_Check()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
///////------------------------
}
}
OEE_Track User control
public partial class OEE_Track : UserControl
{
private static OEE_Track _instance;
public static OEE_Track instance
{
get
{
if (_instance == null)
_instance = new OEE_Track();
return _instance;
}
}
public OEE_Track()
{
InitializeComponent();
}
}
MainForm:
public partial class MainForm : Form
{
private void btn_reg_Click(object sender, EventArgs e)
{
if (!pnl_main_controller.Contains(Safety_Check.instance))
{
pnl_main_controller.Controls.Add(Safety_Check.instance);
Safety_Check.instance.Dock = DockStyle.Fill;
Safety_Check.instance.BringToFront();
}
else
{
Safety_Check.instance.BringToFront();
} }
private void btn_OEE_Click(object sender, EventArgs e)
{
if (!pnl_main_controller.Contains(OEE_Track.instance))
{
pnl_main_controller.Controls.Add(OEE_Track.instance);
OEE_Track.instance.Dock = DockStyle.Fill;
OEE_Track.instance.BringToFront();
}
else
{
OEE_Track.instance.BringToFront();
}
}
What I am trying to do is I have a button called “Button1” on my “Safety_Check” Usercontrol, whenever I press this , I want “Safety_Check” to be disappear on “pnl_main_controller” and bring “OEE_Track” to the panel
There are several solutions for interaction between controls. Controls are classes and like any other class they can interact with each other using their public properties and methods or using some mediator.
In this case, your controls don't need to know each other and don't need to interact to each other directly:
They can ask another object which knows both controls, to do the job for them.
Or they can raise their request notification and the one who subscribed to that notification, will serve it.
To ask another object to do the job for them you have multiple solutions. As an example you can implement a specific interface in the parent form and in the child controls, cast the parent to that specific interface and call a specific method which do the job for you.
For raising the request notification, an easy solution is relying on events. You can create an event in the child control and raise it when you need the parent do something for you. Then in the parent subscribe to that event and do the job.
Example - Using event
I assume you have UserControl1 having Button1 inside and you have handled Click event of Button1. Then you can create Button1Clicked event and raise it when Button1 clicked:
public event EventHandler Button1Clicked;
private void Button1_Click(object sender, EventArgs e)
{
Button1Clicked?.Invoke(this, e);
}
Then in the parent form, subscribe for the event and do whatever you want:
private void userControl11_Button1Clicked(object sender, EventArgs e)
{
//Hide userControl11 and show userControl21
}
Example - Using interface
I assume, you have an interface having a few standard methods:
public interface IDoSomething
{
void DoSomething();
void DoSomethingElse();
}
And you have implemented the interface in your parent form:
public class Form1: Form, IDoSomething
{
// ...
public void DoSomething()
{
//Hide userControl11 and show userControl21
}
public void DoSomethingElse()
{
// ...
}
}
Then in you user control:
private void Button1_Click(object sender, EventArgs e)
{
var f = FindForm() as IDoSomething;
if(f!=null)
f.DoSomething();
}
I want to expand on Reza Aghaei's answer a bit. I think it could get even better than it is now.
First way to do this
If I were you I would have some interface ICheckedView which has at least 1 method to implement like so:
ICheckedView
{
void Continue();
}
Now, we're able to apply this interface to any class in our solution, most likely to views, though. Next, I would make your main form implement this interface and implement the required method. The in this case we want our main form to remove the control from the panel and add a new control. Frankly, our Safety check control doesn't need to (and maybe shouldn't) know about other controls or what happens next. It's just used for flow of control.
Finally, you need to add either a public property, or maybe even a parameter to the constructor for Safety_Check which includes an ICheckedView in it. When your safety check control gets clicked it can tell whoever has been passed into it (we'll say the client) that it must continue.
Second way to do this
It can be done with an action delegate.
If you add an Action delegate to your safety check, you could just pop in any method whose signature matches that delegate (void methodName()). The constructor for your Safety_Check control should include an Action and that Action would get assigned to a private field of the class. Then when it's time to invoke, that action can be invoked directly.
Notes on this method
Because we're probably invoking from the UI thread in the first place, we're probably alright, but you need to think about thread safety here. The invoke required pattern can help you around this.

Changing panel control from inside the panel

I am creating an application using WinForms. I have panel in which I show a user control. Inside this user control I have a button. When I click the button, I want to clear the panel and show a different user control. I am trying to do that using the following code:
private void btnCreateOffer_Click(object sender, EventArgs e)
{
var myControl = new WindowsFormsDemo.View.CreateOffer();
MockUpForm.panMain.Controls.Clear();
MockUpForm.panMain.Controls.Add(myControl);
}
This works from the buttons placed directly in the parrent form, but when I use in inside the user control, it says:
'MockUpForm.panMain' is inaccessible due to its protection level
I suppose it has something to do with private/public classes. But I would rather have the "correct" solution, as opposed to just changing everything to public.
Any suggestions on how this is usually done?
Solution 1 (ugly):
Make panMain public in the designer:
Solution 2 (somewhat better):
Provide public methods to achieve such tasks safely:
// MockUpForm code:
public void ClearPanelControls()
{
panMain.Controls.Clear();
}
public void AddControlToPanel(Control c)
{
panMain.Controls.Add(c);
}
And then call these methods instead of publishing the full panel, which makes possible for example to dispose the whole panel and such things...
To access parent form's control from UserControl You can use delegate and event
something like this....
Windows Form (Parent Form) Code....
public Form1()
{
InitializeComponent();
userControl1.CreateOffer += UserControl1_CreateOffer;
}
private void UserControl1_CreateOffer()
{
var myControl = new WindowsFormsDemo.View.CreateOffer();
this.panMain.Controls.Clear();
this.panMain.Controls.Add(myControl);
}
User Control Code...
internal delegate void CreateOfferDelegate();
internal event CreateOfferDelegate CreateOffer;
public UserControl1()
{
InitializeComponent();
}
private void btnCreateOffer_Click(object sender, EventArgs e)
{
CreateOffer();
}

How to get a method on a main form to get executed on the main form whenever i do some action on a secondary form?

I'm trying to update my data on a main form whenever I change some option in a secondary form.
Possible solution:
Make the method public on Form1 (the main form) like this:
public void updatedata()
{
//data update
}
And then call it on the secondary form:
Form1.updatedata()
This doesn't work and I believe it's because he is trying to update the Form2
I'm using partial classes, but I'm not very well versed on them.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
}
And the secondary one:
public partial class formOpConfig : Form
{
private Form1 Opener { get; set; }
public formOpConfig(Form1 opener)
{ //initialize component
}
}
I feel like surely there is a duplicate question to match this one. But I have been unable to find it.
Given the code you posted, your attempt probably would have worked had you used Opener.updatedata() instead of Form1.updatedata(). But that still would not have been the best solution.
Commenter John Saunders is correct, the right way to do this is to declare an event in formOpConfig, and then have Form1 subscribe to it. That looks more like this:
public partial class formOpConfig : Form
{
public event EventHandler UpdateData;
private void SomethingHappens()
{
// do stuff...
OnUpdateData();
// maybe do other stuff too...
}
private void OnUpdateData()
{
EventHandler handler = UpdateData;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
The above declares an event, and raises that event (invokes the handlers) at the appropriate time (i.e. when SomethingHappens()).
public partial class Form1 : Form
{
private void OpenConfigForm()
{
OpenConfigForm opConfig = new formOpConfig();
opConfig.UpdateData += (sender, e) => updatedata();
}
// Note that this method is private...no one else should need to call it
private void updatedata()
{
//data update
}
}
Here, Form1 subscribes to the event when it creates the instance of formOpConfig (I am assuming Form1 is what creates that instance), and when its handler is invoked, it calls the updatedata() method you've already written.
In this way, the two classes remain decoupled; i.e. they are not actually dependent on each other, more than they need to be (in particular, the formOpConfig class doesn't need to know anything about Form1).
A good way to do this is to use an Event.
This allows you to decouple the forms because they do not even need a reference to each other; basically an event is a way for your second form to tell whoever might be listening (without having to exactly know who) that something of interest happened, and to give them some information about that interesting event that they can use.
The linked article will give you much more detail than the below, which is just a quick idea of how to do it; I would recommend working through the tutorial!
The mechanism by which this occurs is that anyone who wants to know about interesting events on Form2 has to subscribe to the corresponding event on Form2; then whenever Form2 wants to tell its listeners that something has happened, it invokes any event handlers that have been attached to the event.
Because an event can have multiple handlers, it's a really excellent way to keep components in your application decoupled.
Quick demo
(note: code below is off top of head so not tested, no error handling, etc.)
First of all, you need to declare a class that can be used to send the interesting data to listening parties. This class has to inherit from System.EventArgs
public class InterestingEventArgs:EventArgs
{
public string AnInterestingFact {get;private set;}
public InterestingEventArgs(string fact)
{
AnInterestingFact =fact;
}
}
It doesn't matter where you declare this as long as it's visible to both Form1 and Form2.
Next, you have to declare an event on Form2, it needs to be public and should look like this:
public event EventHandler<InterestingEventArgs> SomethingInterestingHappened;
Now you need to decide when you are going to tell interested parties about this event. Let's suppose you have a button on Form2 and you want to raise the event when you click it. So in the Click handler for the button, you might have code like this:
public void btnRaiseEvent_Clicked(object sender, EventArgs e)
{
var fact= txtFact.Text;
var handler = SomethingInterestingHappened;
if (handler!=null)
{
handler(this,new InterestingEventArgs(fact));
}
}
and finally here is how the code might look from Form1 when you are launching Form2, let's say you click a button on Form1 to launch Form2:
public void btnShowForm2_Clicked(object sender, EventArgs e)
{
var child = new Form2();
child.SomethingInterestingHappened+=OnSomethingInterestingHappened;
child.Show();
}
Finally you need to write an event handler on Form1 that will be called when the event is raised:
void OnSomethingInterestingHappened(object sender, InterestingEventArgs e)
{
MessageBox.Show("Did you know? " + e.AnInterestingFact);
}
It looks like you have passed in a reference to a Form1 object in the constructor. Use it:
public partial class formOpConfig : Form
{
private Form1 Opener { get; set; }
public formOpConfig(Form1 opener)
{
Opener = opener;
}
private void updateForm1()
{
Opener.updatedata();
}
}
Form1 is a class, not an object. You can say Form1.updatedata() if you make updatedata() a static method of the Form1 class, but that is probably not compatible with the rest of your code.

ASP .Net User control error handling

We are using asp .Net with C#. I have page(.aspx) consist of multiple Web User Controls(.ascx)
I would like to have an error handling machanism in such a way that if there is any exception in one of the user control, asp .net should show some friendly error message on a control. All other control should render as expected.
Is there any way this can be done without putting place holder on each control which you show/hide in case of exception?
You could do something like this.
An abstract base class with an abstract OnLoad() that each UserControl has to implement. You can use this same model for any event that you want to have shared error handling.
public abstract class BaseUserControl : UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
try
{
OnLoad();
}
catch (Exception)
{
//Custom error handling here
}
}
protected abstract void OnLoad();
}
public class MyUserControl: BaseUserControl
{
protected override void OnLoad()
{
//My normal load event handling here
}
}
1) In app_code, create a class MyPage.cs that inherits Page
class MyPage : Page { }
2) Change the inherits of your pages to MyPage.
public partial class _Default : MyPage { ...
There's an attribute in the web.config you can use to change it if you want
3) Back to MyPage.cs, add the generic error handler of all pages
protected override void OnError(EventArgs e)
{
/* here you can intercept the error and show the controls that you want */
base.OnError(e);
}
First create a base user controlclass which overrides default onerror event.
public class MyControlClass:UserControl
{
protected override void OnError(EventArgs e)
{
//here you sould add your friendly msg implementation
//base.OnError(e); here should remain commented
}
}
Then you can create your user controls:
public class Control1:MyControlClass
{
// ....
// ....
}
So, if any control creates an exception , the rest will keep on working.

Sending string from class to Form1

Although there are some similar questions I’m having difficulties finding an answer on how to receive data in my form from a class.
I have been trying to read about instantiation and its actually one of the few things that does make sense to me :) but if I were to instantiate my form, would I not have two form objects?
To simplify things, lets say I have a some data in Class1 and I would like to pass a string into a label on Form1. Is it legal to instantiate another form1? When trying to do so it looks like I can then access label1.Text but the label isn’t updating. The only thing I can think of is that the form needs to be redrawn or there is some threading issue that I’m unaware of.
Any insight you could provide would be greatly appreciated.
EDIT: Added some code to help
class Class1
{
public int number { get; set; }
public void Counter()
{
for (int i = 0; i < 10; i++)
{
number = i;
System.Threading.Thread.Sleep(5000);
}
}
}
and the form:
Class1 myClass = new Class1();
public Form1()
{
InitializeComponent();
label1.Text = myClass.number.ToString();
}
NO,
I think your form needs to access a reference to Class1 to use the data available in that, and not the other way around.
VERY seldomly a data class should instanciate a display form to display what it has to offer.
If the class is a data access layer of singleton, the form should reference that class, and not the other way around.
Based on the comments in your original post, here are a few ways to do it:
(this code is based on a Winform app in VS2010, there is 1 form, with a Label named "ValueLabel", a textbox named "NewValueTextBox", and a button.
Also, there is a class "MyClass" that represents the class with the changes that you want to publish.
Here is the code for the class. Note that I implement INotifyPropertyChanged and I have an event. You don't have to implement INotifyPropertyChanged, and I have an event that I raise whenever the property changes.
You should be able to run the form, type something into the textbox, click the button, and see the value of the label change.
public class MyClass: System.ComponentModel.INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
public string AValue
{
get
{
return this._AValue;
}
set
{
if (value != this._AValue)
{
this._AValue = value;
this.OnPropertyChanged("AValue");
}
}
}
private string _AValue;
protected virtual void OnPropertyChanged(string propertyName)
{
if(this.PropertyChanged != null)
this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));
}
}
Example 1: simple databinding between the label and the value:
So this time, we will just bind the label to an instance of your class. We have a textbox and button that you can use to change the value of the property in MyClass. When it changes, the databinding will cause the label to be update automatically:
NOTE: Make sure to hook up Form1_Load as the load event for hte form, and UpdateValueButton_Click as the click handler for the button, or nothing will work!
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MyClass TheClass;
private void Form1_Load(object sender, EventArgs e)
{
this.TheClass = new MyClass();
this.ValueLabel.DataBindings.Add("Text", this.TheClass, "AValue");
}
private void UpdateValueButton_Click(object sender, EventArgs e)
{
// simulate a modification to the value of the class
this.TheClass.AValue = this.NewValueTextBox.Text;
}
}
Example 2
Now, lets bind the value of class directly to the textbox. We've commented out the code in the button click hander, and we have bound both the textbox and the label to the object value. Now if you just tab away from the textbox, you will see your changes...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MyClass TheClass;
private void Form1_Load(object sender, EventArgs e)
{
this.TheClass = new MyClass();
// bind the Text property on the label to the AValue property on the object instance.
this.ValueLabel.DataBindings.Add("Text", this.TheClass, "AValue");
// bind the textbox to the same value...
this.NewValueTextBox.DataBindings.Add("Text", this.TheClass, "AValue");
}
private void UpdateValueButton_Click(object sender, EventArgs e)
{
//// simulate a modification to the value of the class
//this.TheClass.AValue = this.NewValueTextBox.Text;
}
Example 3
In this example, we won't use databinding at all. Instead, we will hook the property change event on MyClass and update manually.
Note, in real life, you might have a more specific event than Property changed -- you might have an AValue changed that is only raised when that property changes.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MyClass TheClass;
private void Form1_Load(object sender, EventArgs e)
{
this.TheClass = new MyClass();
this.TheClass.PropertyChanged += this.TheClass_PropertyChanged;
}
void TheClass_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "AValue")
this.ValueLabel.Text = this.TheClass.AValue;
}
private void UpdateValueButton_Click(object sender, EventArgs e)
{
// simulate a modification to the value of the class
this.TheClass.AValue = this.NewValueTextBox.Text;
}
}
There's no reason why you can't have multiple instances of a form, but in this case you want to pass the Class1 instance to the form you have. The easiest way is to add a property to Form1 and have that update the label text:
public class Form1 : Form
{
public Class1 Data
{
set
{
this.label.Text = value.LabelText;
}
}
}
Events and delegates are what you want to use here. Since you tagged this as beginner, I will leave the implementation as an exercise :), but here is the general idea:
Declare an event/delegate pair in your data class.
Create a method in your form to bind to the event.
When "something" happens in your data class, fire the event
The form's method will be invoked to handle the event and can update widgets appropriately
Good luck.

Categories