hi
on a windows form (not WPF) I dynamically create buttons on a flowlayout and I would like to add some properties to them simply to store other values (int and string) with the buttons for latter use.
Button bn = new Button();
bn.Text = "mybutton";
bn.Name = "mybutton";
toolTip1.SetToolTip(bn, "some tip");
bn.Location = new Point(200, 200);
bn.Size = new Size(110, 30);
bn.BackColor = SystemColors.Control;
bn.Show();
flowLayoutPanel1.Controls.Add(bn);
I have about 6 values I would like to store with each button as it is different for each button..
Can this be done?
For non-strongly-typed information, you can possibly use the Tag property. Otherwise, I think you'd have to subclass.
Derive from Button:
public class MyButton : Button
{
public string ExtraProperty {get;set;}
}
Personally, I think this is bad code. Really bad code.
Yes. You can assign data like this to the Button.Tag property (inherited from Control). This property is typed as an object so you can assign anything you want to it.
Alternative, you could inherit from Button.
Like all WinForms controls, Button also has a Tag property, which can be used to store arbitrary objects.
public struct MyButtonData {
public int myInt;
public string myString;
}
...
bn.Tag = new MyButtonData() {myInt = 3, myString = "Hello World"};
...
var data = (MyButtonData)bn.Tag;
You can either:
Create a control, derived from Button, and add the additional properties.
Create a class to encapsulate the data you want to assign to the each button, instantiate the class, and then point the control's "Tag" property at the instantiated object.
The Tag property was designed for this very purpose.
Something you would like to do in this case would be to create a custom control. With a custom control, you have more freedom than with the standard control. Not only will you inherit all the functionality from the existing control you are building your custom control on. You will also have the opportunity to add more functionality and properties to your custom control.
Source: Microsoft - Devloper Network.
https://msdn.microsoft.com/en-us/library/ff723977(v=expression.40).aspx
Related
I am building some applications that use OPC to control some industrial automation. I have decided it might be a good idea to create some custom controls for standard things I will use such as buttons and text boxes. One of my main reasons was that I felt in an ideal pattern the end object i.e. the button is the one who holds information about the OPC item it refers to otherwise in a typical application my Form class gets polluted by tons of variables that are in my mind scoped more global then they should. I started then by using the Tag property of the button but this requires some overhead code that is the same for each instance. I felt like the right thing to do is subclass controls that I would like to use and provide properties to configure each one.
With that context in mind my real question is this. To make it as portable as possible I decided there should a property to define the OPC Group. I declared a property like this
public class OPCButton : Button
{
[Category("OPC")]
public OPCConnectedGroup
{
get { return _OPCGroup; }
set { _OPCGroup = value; }
}
}
This shows up int the property list when I add the control but I am unable to bind this property even though my Form1 contains
public OPCConnectedGroup Connection1 = new OPCConnectedGroup();
I have resolved that the way to solve this is to probably create an additional control like OPCGrp that can be added to a Form then the Controls can reference this. To test I added a property of type Button and sure enough when I added it and browsed to the property it gave me options for all the buttons on the Form. I have no huge problems with this approach I just want to make sure that Im following a prototypical pattern because I will be responsible for maintaining the control library but not always implementing and Im trying to get it down to a 1-2 step process to implement a control.
Thanks
Matt
When defining OPCConnectedGroup you can inherit Component class.
This way if you have a property of type OPCConnectedGroup in your OPCButton, then at design time, you can put instances of OPCConnectedGroup on the form, and then if you choose your OPCButton at designer, that property of type OPCConnectedGroup will show as a drop down list that you can select one of instances that you put on the form for it.
Example:
If I have such MyButton and MyClass:
public class MyButton : Button
{
public MyClass MyClassInstance { get; set; }
}
public class MyClass : Component
{
public string SomeProperty {get;set;}
}
Then you can put some (or one) instance of MyClass on the component tray of the form:
And then if you select MyButton on your form, you can choose one of MyClass instances from in property grid:
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);
I have a custom control that I have created with a bunch standard windows asp controls on it.
Question:
Is it possible to inherit the properties of the parent control into the custom control without re-inventing the wheel?
So for example I have a control with a Button, a TextBox, and a Label.
Normally I can access the properties of that control via Lable1.Text however when these controls are places within a custom control how do I access them without encapsulating all the properties of that control individually.
I was hoping for something like CustomControl1.Lable1.Text or is this not possible
If I use this
public Label lbMovieName
{
get { return this.lbMoveName; }
set { lbMovieName = value; }
}
I get what I need but can you please tell me why I should not do it?
The easiest way is to expose the control through a public read-only property:
public Label MyLabel
{
get { return this.Label1; }
}
However encapsulating just the values you want to expose is definitely a cleaner solution for several reasons:
you can abstract away that actual control type versus being tied to a Label in this case - if you expose the control it will be difficult to swap out the Label with MyNewCoolLabel, for example
You may be exposing more that you want to - the client could change the display properties of the label, etc.
If you are trying to avoid creating properties you can make the controls public (this is not sound OO development). As others have already mentioned you'd be much better served exposing the information that you'd want to share via properties.
The best way and the best practice, I think, is to create properties of your custom control that expose only and exactly what you need. Everything else inside your control should remain private. Something like this:
public string LabelText {
get { return this.Label1.Text; }
set { this.Label1.Text = value; }
}
... and so on for the rest of the properties you need exposed. This will give you nice intellsense response in the designer as well.
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);