How to convert from 'string' to 'System.Windows.Forms name - c#

For example
private void tab_Control_SelectedIndexChanged(object sender, EventArgs e)
{
var menuItem = (TabControl)sender;
Selected_tab(tab_Control.SelectedTab.Name);
}
void Selected_tab(string tabname)
{
TabPage _tabname = tabname; // Error need to be converted
this.tab_Control.SelectedTab = _tabname;
}

In this particular case, you can write
tab_Control.SelectedTab = tab_Control.TabPages[tabname];
In general, if you know that the control you're looking for is directly inside of some container (such as a GroupBox or the form itself), you can write
someContainer.Controls[controlName];
If you don't know what the control's parent is, you can write
this.Controls.Find(controlName, true);
The second parameter tells it to recursively search all containers.

Related

Retrieve values that are outside the context

I dynamically create controls and I'd like to be able to use them outside of the context.
For example a dynamically created label :
i = 0;
while (readerBE.Read())
{
Label labelBE = new Label();
labelBE.Name = "labelBE" + i;
labelBE.Text = readerBE["codeArticleComposant"].ToString();
labelBE.Cursor = Cursors.Hand;
labelBE.Click += new EventHandler(this.labelBE_Click);
i++;
}
And when I try to use the OnClick event to retrieve a value like this :
private void labelBE_Click(object sender, EventArgs e)
{
Console.WriteLine(labelBE.Text);
}
labelBE does not exist in the current context.
You can cast the sender argument:
private void labelBE_Click(object sender, EventArgs e)
{
Label labelBE = (Label) sender;
Console.WriteLine(labelBE.Text);
}
But one thing, you have a while-loop and you always create this Label and you never add it to any container control (like GroupBox, Panel or Form). So you would never create multiple and either the while-loop is wrong and should be replaced with an if or you should add the labels to a collection or parent control (well, you should do that anyway).
You can use the sender object that generated the click :
private void labelBE_Click(object sender, EventArgs e)
{
Console.WriteLine(((Label)sender).Text);
}
However I suggest you read more about Variable scope.
Your problem is that you create a variable inside a method, so this variable is no more accessible once you leave it.

Remove control created at runtime

I wrote some code to create an additional textbox during runtime. I'm using the metro framework, but this shouldn't matter for my question.
When you click a button, a textbox is being created by a private on_click event:
private void BtnAddButton_Click(object sender, EventArgs e)
{
MetroFramework.Controls.MetroTextBox Textbox2 = new MetroFramework.Controls.MetroTextBox
{
Location = new System.Drawing.Point(98, lblHandy.Location.Y - 30),
Name = "Textbox2",
Size = new System.Drawing.Size(75, 23),
TabIndex = 1
};
this.Controls.Add(Textbox2);
}
What I want to do now is to use the click event of another button, to remove the Textbox again. What I am not sure about is, if I have to remove just the controll or also the object itself. Furthermore I can neither access the Textbox2 Control nor the object from another place.
private void BtnRemoveTextbox2_Click(object sender, EventArgs e)
{
this.Controls.Remove(Textbox2);
}
This does not work, since the other form does not know about Textbox2. What would be the best way to achieve my goal? Do I have to make anything public and if so, how do I do that?
You have to find it first before you choose to remove it.
private void BtnRemoveTextbox2_Click(object sender, EventArgs e)
{
MetroFramework.Controls.MetroTextBox tbx = this.Controls.Find("Textbox2", true).FirstOrDefault() as MetroFramework.Controls.MetroTextBox;
if (tbx != null)
{
this.Controls.Remove(tbx);
}
}
Here, Textbox2 is the ID of your textbox. Please make sure you're setting the ID of your textbox control before adding it.
You need to find those controls using Controls.Find method and then remove and dispose them:
this.Controls.Find("Textbox2", false).Cast<Control>().ToList()
.ForEach(c =>
{
this.Controls.Remove(c);
c.Dispose();
});
Since the control was created in another form, the current form has no way of knowing it by its instance name.
To remove it, loop through all controls and look for its Name:
private void BtnRemoveTextbox2_Click(object sender, EventArgs e)
{
foreach (Control ctrl in this.Controls)
{
if (ctrl.Name == "Textbox2")
this.Controls.Remove(ctrl);
}
}

Creating controls on runtime - pass data

In Windows Forms project I have this method to set some properties of dynamically created control. In this case I also need to show a tooltip when user hovers mouse over it. This works ok except for one thing, I have no idea how to pass the value of w["text"] to control_MouseEnter.
private void SetProp(ref Control obiekt, Dictionary<string, string> w)
{
obiekt.Name = w["id"];
obiekt.Location = new Point(Convert.ToInt16(w["wspx"]), Convert.ToInt16(w["wspy"]));
obiekt.Height = Convert.ToInt16(w["wys"]);
obiekt.Width = Convert.ToInt16(w["szer"]);
if (w["text"] != "")
{
obiekt.MouseEnter += new EventHandler(control_MouseEnter);
obiekt.MouseLeave += new EventHandler(control_MoouseLeave);
}
}
private void control_MouseEnter(object sender, EventArgs e)
{
toolTip.Show("how to pass a value here ??", (Control)sender, 5000);
}
I have no idea has to pass the value of w["text"] to control_MouseEnter.
You can either link your data with target control directly (for example via Control.Tag property) or indirectly (for example, via global variable/dictionary), or use anonymous delegate and closure to create the local data-context:
obiekt.MouseEnter += (s,e) => {
tooltip.Show(w["text"], (Control)s, 5000);
};
Is there a way to use EventArgs somehow?
No, you can't. Because the args are instantiated within the Control's code exactly at the moment when the mouse event occurs, and you can't control the EventArgs creation from event-subscription point.
How about setting the text into Tag member of Control object?
S.th. like object.Tag = w["text"]; and show it with event handler

Add listview items from other form (using objects)

I want to get some data to fill a listview control, but this data it's determined in other form. This is what I code in form1 (Nuevo_Credito):
private void combo_cliente_SelectionChangeCommitted(object sender, EventArgs e)
{
Credito_Grupo ventana = new Credito_Grupo(combo_cliente.SelectedItem);
ventana.ShowDialog();
}
public void AgregaIntegrantes(string id, string nombre, string monto)
{
ListViewItem elem = new ListViewItem(id);
elem.SubItems.Add(nombre);
elem.SubItems.Add(monto);
listView_integrantes.Items.Add(elem);
}
I'm invoking form2 (Credito_grupo) as show dialog window, then I want to retrieve some values and pass them to Form1 using the public method "AgregaIntegrantes". So in form2 I did the following:
public Credito_Grupo(dynamic item)
{
this.id = item.IDCliente;
this.nombre = item.NomComp;
InitializeComponent();
}
private void Credito_Grupo_Load(object sender, EventArgs e)
{
text_nombre.Text = this.nombre;
}
private void button_AgregaCliente_Click(object sender, EventArgs e)
{
Nuevo_Credito obj = new Nuevo_Credito();
obj.AgregaIntegrantes(id.ToString(), nombre, text_monto.Text);
this.Close();
}
When the event button_AgregaCliente_click is triggered I need to add the data to listview in form1 using the method described above, but none data is added. I found a solution using delegates here 3077677, is there an approach using objects?
You have an error in button_AgregaCliente_Click method (the last one in the listing). You create a new Nuevo_Credito form there, and pass the data to listview. It looks OK. But this newly created Nuevo_Credito form does exist only in the local variable, so then you throw it away without displaying it when button_AgregaCliente_Click finishes.
I think you need to delete this line: Nuevo_Credito obj = new Nuevo_Credito();
You need to get your real Nuevo_Credito form, not create a new one here.
You can send this from your Nuevo_Credito to the constructor of the Credito_Grupo form. Then you can use it to call back to the original Nuevo_Credito. This approach is based only on objects, and not delegates. As you wanted. :-)

add behavior to group of windows form controls

I'm trying to mimic the web functionality of having a label over a textbox that shows the type of value the textbox should contain. I can add the events individually but I'm wondering if there is a way to add 'Behavior' to a set of controls.
Please see example code:
private void labelFirstName_Click(object sender, EventArgs e)
{
HideLabelFocusTextBox(labelFirstName, textBoxFirstName);
}
private void HideLabelFocusTextBox(Label LabelToHide, TextBox TextBoxToShow)
{
LabelToHide.Visible = false;
TextBoxToShow.Focus();
}
private void textBoxFirstName_Leave(object sender, EventArgs e)
{
if (String.IsNullOrEmpty(textBoxFirstName.Text))
labelFirstName.Visible = true;
}
private void textBoxFirstName_Enter(object sender, EventArgs e)
{
labelFirstName.Visible = false;
}
You could subclass the text box control (write your own that inherits a textbox)
Btw, i have thought about this and i would take another approach:
i would override the text box's paint handler and when the textbox contains no information, draw an info string into it.
Something like:
using System;
using System.Windows.Forms;
using System.Drawing;
class MyTextBox : TextBox
{
public MyTextBox()
{
SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
if (string.IsNullOrEmpty(this.Text))
{
e.Graphics.DrawString("My info string...", this.Font, System.Drawing.Brushes.Gray, new System.Drawing.PointF(0, 0));
}
else
{
e.Graphics.DrawString(Text, this.Font, new SolidBrush(this.ForeColor) , new System.Drawing.PointF(0, 0));
}
}
protected override void OnTextChanged(EventArgs e)
{
Invalidate();
base.OnTextChanged(e);
}
}
Tie Behaviour
You can tie the feature/behaviour closer to the TextBox control by using extension methods. This simple solution might make it feel more tightly knit:
// NOTE: first parameter "this TextBox thisText"- these are all extension methods.
static public void AssignLabel(this TextBox thisText, Label companionLabel) {
thisText.Tag = companionLabel;
// HOOK UP EVENT AT THIS POINT, WHEN LABEL IS ASSIGNED (.NET 3.x)
thisText.Leave += (Object sender, EventArgs e) => {
LeaveMe(thisText); // Invoke method below.
};
}
static public void FocusText(this TextBox thisText) {
if (! ReferenceEquals(null, thisText.Tag))
(Label)thisText.Tag).Visible = false;
thisText.Focus();
}
static public void LeaveMe(this TextBox thisText) {
if (String.IsNullOrEmpty(thisText.Text))
((Label)thisText.Tag).Visible = true;
}
//etc.
and then use your textbox instances like so:
Label overlay1 = new Label(); // Place these appropriately
Label overlay2 = new Label(); // on top of the text boxes.
Label overlay3 = new Label();
TextBox myTextbox1 = new TextBox();
TextBox myTextbox2 = new TextBox();
TextBox myTextbox3 = new TextBox();
// Note: Calling our extension methods directly on the textboxes.
myTextbox1.AssignLabel(overlay1);
myTextbox1.FocusText();
myTextbox1.LeaveMe();
myTextbox2.AssignLabel(overlay2);
myTextbox2.FocusText();
myTextbox2.LeaveMe();
myTextbox3.AssignLabel(overlay3);
myTextbox3.FocusText();
myTextbox3.LeaveMe();
//etc...
How it Works
The code is cleaner and applies to all TextBoxes you instantiate.
It relies on the the .Tag property of the TextBox class to store a Label reference into (so each TextBox knows its label), and also extension methods introduced with .NET 3.x which allow us to "attach" methods onto the TextBox class itself to tie your behaviour directly to it.
I took your code and produced almost the same thing with tweaks to turn it into extension methods, and to associate a Label with your Textbox.
Variation
If you want to attach the same method to other controls (and not just the text box) then extend the base Control class itself like:
static public void LeaveMe(this Control thisControl) { //...
You could always create a user control that does this. Put both the TextBox and the Label inside the control and code up the logic inside the user control. That way every instance of that control will behave the same.
Another option might be to use an Extender Provider. These basically let you add a behavior to any control (though these can be limited if I remember right) at design time. The ToolTip is an example of an Extender Provider that is already floating around in the framework. I used these quite a bit once upon a time to do things like add support for getting the text values of controls from a resource file.
I would subclass the regular textbox and add properties which allow you to either find the associated label or set a reference to the associated label directly.
Typically in winform projects, I subclass all controls before adding them to my forms, so I can add common functionality very easily without having to change forms in the future.

Categories