I have a user control class that has the following behavior (pretty normal stuff)
public class C1
{
//controls with auto generated code in the designer file that I can access
//such as with the following action (for example)
string s1 = txtThing.Text;
}
It is created (and destroyed, along with other classes) dynamically via a call in the parent form like:
public class MainForm
{
UserControl activeControl = null;
//...later on...
activeControl = new C1(params...)
//later on, as a new control is needed
panel.Controls.Clear();
}
I need to dynamically add an event handler to the text boxes text changed event, and the event lives in the MainForm class. So I want to do something like
activeControl.txtThing.TextChanged += new EventHandler(MyCustomHandler);
But the text box is obviously private. If I creat e property to get it (or even just the text) in the C1 class, I still cannot "get" the control pr property I need and I have no idea why... The only properties I can see (with activeControl. in intellisense) are the standard user control properties, and none of C1's properties. I'm not sure why...
Help is appreciated of course, hopefully you see what I'm trying to get at.
After you created a property in the C1 class, you need to cast activeControl.
if (activeControl is C1)
(activeControl as C1).TxtThingProperty.TextChanged += new EventHandler(MyCustomHandler);
Related
I have code that dynamically loads (and destroys) user controls of different types onto a form as they are needed. The user control uses properties from its parent to load certain values into controls such as textboxes and check boxes. The issue is that in the line:
activeControl = new userControl1(params...);
my constructor is obviously going to try loading fields that don't exist yet (they belong to the parent form) since it hasn't been added to the parent form until after userControl1 is created.
I tried solving this using the ParentChanged event of the user control so it waits until its parent is set before loading fields. The problem here is when I destroy userControl1 and create a userControl2, the parent changes and it tries to load the fields from the null ParentForm (the exact problem I had originally.
Is there a preferred way to tackle this? Clearly, I could just add something like
if(this.ParentForm == null) { return; }
to the ParentChanged event or something along those lines. But this feels neither elegant nor safe. Am I overlooking some event or preferred way to accomplish this?
While it is not necessarily bad to check for null references and divert the code accordingly (e.g. not try to reference a missing object), the better approach here is to decouple your UserControl classes from their parents.
That is, these UserControl classes should not have any awareness of their parent form types at all. To do otherwise is to negate one of the major benefits of OOP: code reuse. With your current design, even if you get it to work without crashing, you can't ever use these UserControl objects except in the context of this specific parent form type.
You may think today that that's okay, that you'll never want to use them in any other context. But the future is hard to predict. You may decide, for example, that you want a variation on the parent form that should still use these same UserControl objects.
What you should be doing is exposing the UserControl state via public properties, and then allow the parent form to initialize those as necessary.
Here's a very simple example (I'm omitting the Designer-created codeā¦I assume that you can infer from the field names what I mean):
partial class UserControl1 : UserControl
{
/* ... */
public bool IsMyFlagChecked
{
get { return checkBox1.Checked; }
set { checkBox1.Checked = value; }
}
/* ... */
}
partial class ParentForm : Form
{
/* ... */
private void SomeMethodThatAddsUserControl1()
{
UserControl1 uc1 = new UserControl1;
uc1.IsMyFlagChecked =
this.SomeParentFormPropertyUserControl1UsedToReferenceDirectly;
// other initialization for uc1...
Controls.Add(uc1);
}
/* ... */
}
(Note that without a good, minimal, complete code example that illustrates your question, I can't provide a more detailed code example than the above. If this doesn't seem to address your question, please edit it so that it provides more detail, including a better code example).
I have an issue when it comes working with events and/or delegates. I saw very similar questions but still the real implementation is not clear to me. So please when you answer be more specific so I can try and eventually understand how exactly creating/handling of public/custom events work by doing it in a code I know.
What I have is a User Control which is simply a text box and a button I need to change a record in a database using the value from the text box. I'm using this control for many forms so I need to know which entity exactly I'm using and be able to call it's own save method. Doing all that will be easier if I just can use the click event of the button from my User Control and then call the Save() method of the current form.
This is my User Control :
namespace UserControls.CommonControls
{
public delegate void ClickMe(string message);
public partial class ChangeCode : UserControl
{
public event ClickMe CustomControlClickMe;
public ChangeCode()
{
InitializeComponent();
}
private void btnChange_Click(object sender, EventArgs e)
{
if (CustomControlClickMe != null)
CustomControlClickMe("Hello");
//ToDo fill
//MessageBox.Show("To Do: Write the busieness logic.");
}
public void SetTextBoxMask(MaskedTextBox txtBox)
{
txtChange.Mask = txtBox.Mask;
}
}
}
I post it with the last attempt I made to try and implement what I need.
This is one of the form that need to use the Click event from the User Control and more specific the Constructor because if I understand right there is the place where I have to subscribe for the event :
public MaterialEdit()
{
InitializeComponent();
UserControls.CommonControls.ChangeCode. += new ClickMe(button2_Click);
}
UserControls.CommonControls.ChangeCode - this is how I reach my User Control it's named ChangeCode.
From what you pasted it is not clear that you added ChangeCode control to your form. To use the control and it's events and properties, first you must create new instance to it and add it to the form. This is done:
In designer, by dragging control from Toolbox to the form
In code editor, by invoking control constructor and adding new object to control collection
Only then can you handle event of that object. Let's say that you dropped ChangeCode control to a form, and that Visual Studio named it ChangeCode1. You attach a handled to CustomControlClickMe event like this:
ChangeCode1.CustomControlClickMe += new ClickMe(button2_Click);
Code you pasted (UserControls.CommonControls.ChangeCode. += new ClickMe(button2_Click);) is incorrect for several reasons:
Syntactically, left hand side expression ends with . which makes it incorrect assignment target (UserControls.CommonControls.ChangeCode.)
Event name is not provided, only the control name (you need to end left hand side of assignment with what you want to assign to - .CustomControlClickMe)
You are trying to attach handler to a class and not an object
I have two projects in this solution: ProjectA and ProjectB. ProjectA is the main start-up project, and has a reference to ProjectB.
ProjectA has a file called MainForm.cs, which contains a textbox and the main UI.
ProjectB has a class inside Shapes.cs, containing a particular structure we're using. Shapes.cs contains an event that is fired when the user changes some text for that object.
What I need to do is catch that text and set a textbox in MainForm.cs to that text. Is there a way we can do that? Basically I don't see any reference to the main form inside Shapes.cs. I would like to do something like this:
( Shape1.Parent as MainForm ).TextBox1.Text = Shape1.Name;
, assuming the user types a string that gets stored in Shape1.Name. I need to escalate it to the main form.
I have searched around for other questions, and the closest lead I found was Matt Hamsmith's answer on this question. But if it is a good approach I should follow, I do not know how to assign an event handler in the main form to an event in the separate class. I would appreciate any help.
Thanks.
If the form is made up child controls, it should be listening to events on those controls, rather than the controls trying to cast their parent as a particular type. Doing that means your control will only ever work on that Form. It breaks encapsulation.
Listen to an event like this:
public class MainForm : Form
{
Shape _shape1 = new Shape();
public MainForm()
{
InitializeComponent();
_shape.ShapeNameChanged += HandleShapeNameChanged;
}
public void HandleShapeNameChanged(object sender, ShapeChangeEventArgs e)
{
textBox1.Text = e.NewName;
}
}
public class Shape
{
public event EventHandler<ShapNameChangedEventArgs> ShapeNameChanged;
}
I've left it for you to:
Define the ShapeNameChangedEventArgs object to contain whatever state you want it to.
Invoke the event when something on your control changes.
Good luck!
I have a WinForm application. On the main form there are a number of controls, such as labels, textboxes, etc.
If I have another class, within the same assembly, how can I access those controls?
For example from my new class, I want to update a label in Form1?
In the property of the label (or any control) set the "Modifiers" option to "Public"
Now you can access the label from the object of the Form
Form1 f = new Form1()
f.lblMyLabel.Text = "My Text"
One way would be to create public properties in your Form1 class that expose the controls you are trying to modify
For example, if your Label is called label1 in the designer then you could do something like this:
public Label MyForm1Label { get { return label1; } }
select the control which you wants to access from another class/form. go to its property and set its modifiers value to "internal" (if you want to use it only in same assembly) .
now where ever in same assembly you wants to use it just create an object of that form like
myForm objform = new myForm();
objform.txtName.Text="any text";
then you can show that form using objform.show(); or objform.showdialog();
but i think this will not solve you issue because what i feel is that your form is already showing on screen and from another form/class you wants to change its label/textbox's value
so for this you will have to take that current object of form otherwise it will not show any changes on currently showing form.
so i think singleton pattern will give you perfect solution.
just create class and in that class create a static object of that form and than create a static function and check if object is already initialized that do not initialize it and use existing otherwise initialize it.
there are lots of other solutions also exists like by creating public property but you will have to use reference of same object of currently showing form to see changes reflect to currently showing form
Apart from the solutions which were already mentioned you can create some public method to your Form that will provide desired functionality (Might be good if some change has to be displayed in several controls - your other classes don't have to remember which one to change)
public void SetSomething(int value)
{
Control1.value = value;
Control2.value = value;
...
}
The easyiest way is to use:
Form1 f = new Form1()
f.lblMyLabel.Text = "My Text"
Therefore, you have to set the Form1 Label "lblMyLabel" just to public. I have done it with a richTextBox.
enter image description here
I have a simple user control with a text box and label in it. I created public properties to access the text in the textbox when I use the user control in another form.
My problem is the property is returning null value when I call it in the form. Am i missing anything?
My property is as follows::
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string rtnTxtMake
{
get
{
return txtMake.Text;
}
set
{
txtMake.Text = value;
}
}
}
and in the next forms button click event i call the property as follows
UserControl1 Usc = new UserControl1();
string Make = Usc.rtnTxtMake;
MessageBox.Show(Make)
UserControl1 Usc = new UserControl1();
string Make = Usc.rtnTxtMake;
If your user control has by default an empty textbox field, then it seems correct that the above two lines of code would return either null or String.Empty (check via String.IsNullOrEmpty), since you explicitly create a new instance of your user control.
I suppose what you really want is this:
You have inserted a user control into a form in the Designer. Let's call this user control instance ctlUser.
You have a button with a Click event handler. The last few lines of code in your question are from that handler method.
In the handler, you wouldn't create a new instance of your user control (Usc) but refer to the one that you previously inserted into your form, ctlUser. Then things should work as expected.
Your UserControl must be added to the Controls collection of a parent Form/Control before it can be properly initialized. Normally you would not write the code yourself that creates and adds the UserControl.
Instead, first build your project, then go to the Deisgner view of your main form and look at the Toolbox.
Your UserControl name (and an icon) should appear towards the top of the toolbox, and you can simply drag it to the main form. The Windows Forms designer will automatically generate the needed initialization code for you.
You should not create a new instance of your control in your button click event handler. Using the Designer approach to create your control you can simply access the existing instance of your control as follows:
public void button_Click(object sender, EventArgs e)
{
// myUserControl1 has already been created and initialized by the Deisgner generated code
// Note the name 'myUserControl1' is just an example, yours may be different.
string controlText=myUserControl1.rtnTxtMake;
// Or to change the UserControl textbox value
myUserControl1.rtnTxtMake="Testing";
}
What exactly to you mean when you say that the property is returning a null value? Is it actually null, or is your MessageBox simple showing empty?
I quickly duplicated your code and it behaves exactly as expected - the MessageBox shows, but it is empty because the default value of the Text property of the TextBox control is an empty string.
Also, the way you are approaching this is a little unusual.
Firstly, the line:
UserControl1 Usc = new UserControl1();
You do not generally need to instantiate a user control like this. Instead you can drag the control from the toolbox onto the design surface of your form. This will then take care of instantiating and initialising your control for you.
I think that this is actually your problem - when you include the line of code above, you are creating a new instance of the user control, and this is is no way realted to the user control that you have dragged onto the designer.
If you go to the designer view of your form and click on the user control, you should see a properties window somehere. If you do no, then either select it from the View menu, or press F4. In the list of properties, there should be one "Name" this is the programatic name generated for your user control. You can change this here if you want, but when you refer to this control in the rest of the form, this is what you must use.
Secondly, the next two lines:
string Make = Usc.rtnTxtMake;
MessageBox.Show(Make)
You can access the property rtnTxtMake directly. Unless you later need to access the Make string in the rest of your code, then directly accessing the property would usually be considered better style.
MessageBox.Show(userControl.rtnTxtMake);