I have made a winform application in c#. Now I added a class named Main_Form_1.
In Main_Form, there are some click events that I copied in Main_Form_1.
// Main_Form.cs
public partial class Main_Form : Form
{
...
// code here
...
}
// Main_Form_1.cs
public partial class Main_Form : Form
{
private void SomeButton_Click(object sender, EventArgs e)
{
...
}
}
Now I want to assign this SomeButton_Click event, but I can not see the events in the property window. How can I assign this event to SomeButton?
I'm pretty sure you mean the event handler SomeButton_Click here. You can add it to the Click event of button "SomeButton" with: SomeButton.Click += SomeButton_Click;
Related
I know that VS will open an eventhandler stub by doubleclicking on an event.
I found the underlying event declaration in InitializeComponent of the form on which the button is located.
this.buttonWorkOn.Click += new System.EventHandler(this.buttonWorkOn_Click);
Can I use this event declaration (of Visual Studio) and register another eventhandling method with it?
Upon instantiation of that other form its eventhandling method would need to register itself with the click event of the button on the main form.
I have no clue how to do that even though I have read quite a bit about delegates and events and in principle I do understand how it works.
Thank you
If you right click on an event handler in the code editor and browse the definition you will find the way that it is declared, which you can then use in your own code.
For example, the declaration for a Button's Click event is:
public event EventHandler Click;
You can add these yourself and use them from other places to respond to events in any class you create.
Here's a sample form with a single button (added via the designer) that when clicked will raise its own event:
public partial class Form1 : Form
{
public event EventHandler ButtonClicked;
private void RaiseButtonClicked()
{
if (ButtonClicked != null)
ButtonClicked(this, EventArgs.Empty);
}
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
RaiseButtonClicked();
}
}
In another class you can then add a handler to that:
public class Responder
{
public Responder(Form1 form)
{
form.ButtonClicked += OnButtonClicked;
}
private void OnButtonClicked(object sender, EventArgs args)
{
MessageBox.Show("Button was clicked");
}
}
Now every instance of the Responder class will tell you when the button is clicked on the form.
By "Double clicking on an event", visual studio will generate an event handler for you. What you don't see is that visual studio also subscribes the generated event handler to the event, by adding a line of code in your designer file.
If goes something like this:
Double click 'clicked' event
Visual studio opens up your code file, and you have a new button1_clicked method, which is your event handler.
Your designer is updated with a line like button1.Clicked += button1_clicked
If you want to do manual event subscriptions, you can do so from your code file, by adding something like <formelement>.<event> += <eventhandler>. If you cant see available events in your intellisense, you can always check the online documentation. MSDN
(You should never change your designer file, as this is a generated file)
If you like to get multiple methods been executed when an event occurs you can simply add all of them in your code (or you can even add the same method multiple times):
private void DoSomething(object source, EventArgs eventArgs)
{
Console.WriteLine("Something happened.");
}
private void DoSomethingElse(object source, EventArgs eventArgs)
{
Console.WriteLine("Something else happened.");
}
private void AttachToEvent()
{
button1.Clicked += DoSomething;
button1.Clicked += DoSomethingElse;
button1.Clicked += DoSomething;
}
This would print out:
Something happened.
Something else happened.
Something happened.
OK – it was not my application, I just tried to improve on it.
Anyway, the question was who owns whom and who is visible where.
On the Mainform are controls for user input.
On MainForm a variable of type "class preview" is declared:
Preview pv
For the Preview class I added an event declaration named WorkOn:
public class Preview
{
#region "Variables"
#region "PublicEvent"
public event EventHandler WorkOn;
}
Then in the MainForm, the variable pv – declared as a class field - is instantiated within a method.
pv = new Preview()
after which the user input in the controls of the main form is checked and when ok saved in the variables of the preview class.
Then, the PreviewForm is instantiated within the preview class, with the instance of the owning class (preview --> as instance pv) passed as a variable to the instantiation of the PreviewForm.
I had to create this overloaded constructor because from the PreviewForm an eventhandler must be registered with the preview class to make this work – as I realized.
formPreview formPreview = new formPreview(this);
// this --> is the class preview, the instance pv
// Instantiation of FormPreview
public formPreview(Preview preview)
{
InitializeComponent();
this.preview = preview;
// now for the event in the preview class an eventhandling method
// of the preview form is registered:
preview.WorkOn += formPreview_Close;
}
This is the registered method of FormPreview:
private void formPreview_Close(object sender, EventArgs e)
{
this.Close();
}
I was reminded again that events can only be raised from the class that publishes the event. So I had to create a public event raising method within the class preview – here named OnWorkOn:
public void OnWorkOn()
{
if (WorkOn != null)
WorkOn(this, EventArgs.Empty);
}
And finally I could trigger the event from the MainForm within the button to whose underlying event I planned to register the eventhandling method of the PreviewForm in the first place.
Only now I had to use the class variable pv of the MainForm as it is the medium between the MainForm and the PreviewForm:
public void buttonWorkOn_Click(object sender, EventArgs e)
{
pv.OnWorkOn();
// raising the event, informing whoever is registered to it
//...
}
So the design of the application did not allow for registering any eventhandling method of the preview form directly on the MainForm. That was the problem and I didn't quite see through the whole design yet.
Well – this is the outcome of a german C# tutorial – the only german one I know of.
You'll find it here:
[https://www.youtube.com/watch?v=-zCiwcgxMHw&list=PLvvL1HRuCBItyw45XnCqEXzuegKQd3MfL][1]
The code is not available for download anymore, but I could provide it as I am through.
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.
I am creating a C# WinForms user control. There will be times when the user control will need data from the form it's contained in. How do I go about having the user control tell the form containing it that it needs some data?
Thanks!
You can subscribe the form to an event raised on the UserControl.
Your archiecture dictates where and when you need to subscribe to the data event. We can't answer that without knowing a little more about how your whether you are adding the control at runtime or design time. Each case will require a little derivation. From the perspective of adding your control at runtime, you could do something similar to the following:
// Your sample control
public class MyUserControl : Control
{
public event EventHandler<EventArgs> INeedData;
public Data Data {get; set;}
private class DoSomething()
{
if(INeedData!=null) INeedData(this,null);
}
}
...
// Your Form, in the case that the control isn't already added.
var _myUserControl = new MyUserControl();
private void Form1_Load(object sender, EventArgs e)
{
_myUserControl.INeedData += new EventHandler<EventArgs>(MyUserControl_INeedData);
this.Controls.Add(myUserControl);
}
void MyUserControl_INeedData(object sender, EventArgs e)
{
_myUserControl.Data = SomeData;
}
Create a custom event in the user control and have the form hook into it. If you need custom event arguments, you can create those too.
In user control:
//Define your Custom Event argument
public class MyEventArgs : EventArgs
{
//Define some fields of your custom event argument
private int m_SomeValue = 0;
//Define some properties of your custom event argument
public int SomeValue
{
get { return m_SomeValue; }
set { m_SomeValue = value; }
}
}
//Define the event handler data type
public delegate void MyEventHandler(object sender, MyEventArgs e);
//Define the object which holds the outside event handlers
public event MyEventHandler SomeEvent;
//Define the function which will generate the event
public virtual void OnSomeEvent(MyEventArgs e)
{
if (SomeEvent != null)
SomeEvent(this, e);
}
.
. //Then later in the control
.
{
//We need new data
//Create the event arguments
MyEventArgs newEvent = new MyEventArgs();
//Set the values
newEvent.SomeValue = 17;
//Call the event generating function
OnSomeEvent(newEvent);
}
In your form just use something like:
myControl.SomeEvent += new MyEventHandler(handlerName);
Since your event is public, you should see it in the Properties window of your control as well.
You can fancy up the event using Metadata attributes, but I leave it up to you to discover these.
Create an event on the user control where the event args are editable. Let the form attach a handler to that event, which updates those fields. Use those fields in the OnEvent method.
[untested]
eg.
public delegate void NeedsUserDataEventHandler(object sender, NeedsUserDataEventArgs args);
public class NeedsUserDataEventArgs : EventArgs
{
public UserData UserData { get; set; }
}
// In Control
public event NeedsUserDataEventHandler NeedsUserData;
public void OnNeedsUserData(NeedsUserDataEventArgs args)
{
NeedsUserDataEventHandler handler = NeedsUserData;
if (handler != null) handler(this, args);
// store your data somewhere here
}
// In Form
public override void OnLoad(object sender, EventArgs args)
{
control.NeedsUserData += ControlNeedsUserData;
}
public override void OnClosed(object sender, EventArgs args)
{
control.NeedsUserData -= ControlNeedsUserData;
}
public void ControlNeedsUserData (object sender, NeedsUserDataEventArgs args)
{
args.UserData = // set whatever here
}
Seems a bit vague to me, but:
Make it an event in the containing WinForm, so that every time some data is ready all the subscribers can be notified in a one-to-many model; or make it an event in the subscribed control, in a one-to-one model, in which it calls the container's method that retrieves such data?
It's dependent on when that data needs to be pushed to the UserControl. Are there events taking place on the Form that will drive the need to move data within the UserControl? If so...simply grab your instance at that point and push the data down to the UserControl via a public property.
If this is a case where events are not being used or the Form in some fashion or another "receives the data" then exposing an event on the Form such as...
public event DataHandler ReceivedData;
...and allow the UserControl or any other container to register for the event and receive the data via your custom event args. Pushing the event into the UserControl and forcing the Form to latch onto the UserControl seems backwards since the Form is the initiator of the data.
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.
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.