c# textbox shows object name instead of value - c#

I have a form written in c#, with various drop down lists, but I'm having problems with a listbox on the form. I need to populate a textbox with the values selected from the listbox when I double click on them. I've got the click event working, but the textbox will only populate with the object name, not the value from the listbox
i.e.
'System.Windows.Controls.SelectedItemCollection'
instead of the actual value.
Here is the entire code block I'm working on:
I should have just done this at the start - here is the complete code block I'm working on:
else if (theValue.FieldName.Equals("UIPathList", StringComparison.OrdinalIgnoreCase) == true)
{
int nRow = 14;
Button theUIPathOptionsButton = new Button();
TextBox theOldValueTextBox = AddLabelAndOldValue(theHelper, nRow, theValue);
theOldValueTextBox.Text = theValue.OldValue.Replace(",", "," + Environment.NewLine);
theUIPathOuterStackPanel = new StackPanel
{
Visibility = Visibility.Visible,
Orientation = Orientation.Vertical,
Background = new SolidColorBrush(Colors.White),
ClipToBounds = true,
};
theUIPathOptionsInnerStackPanel = new StackPanel
{
Visibility = Visibility.Visible,
Orientation = Orientation.Horizontal,
Background = new SolidColorBrush(Colors.White)
};
theUIPathOuterStackPanel.ClipToBounds = true;
TextBox theNewTextBox = new TextBox
{
TabIndex = nRow,
TextWrapping = TextWrapping.Wrap,
AcceptsReturn = true,
};
theNewTextBox.Clear();
theNewTextBox.MouseDoubleClick += MultiLineChildDatapointList_HandleMouseDoubleClick;
theNewTextBox.Focusable = true;
theNewTextBox.HorizontalAlignment = HorizontalAlignment.Stretch;
theNewTextBox.Width = 365;
theNewTextBox.PreviewKeyDown += theGetMetadataHelper.Preview_KeyDown_IsMultilineText;
theNewTextBox.Tag = theValue;
ListBox theUIPathOptionslistBox = new ListBox();
theUIPathOptionslistBox.Items.Add("RuntimeDefaults");
theUIPathOptionslistBox.Items.Add("CommonSettings");
theUIPathOptionslistBox.Items.Add(InputDatapointManager.CONST_CHANGE_RECORD_CHANGES_CLEAR_VALUE);
theUIPathOptionslistBox.TabIndex = nRow;
theUIPathOptionslistBox.SelectionMode = SelectionMode.Multiple;
theUIPathOptionslistBox.ClipToBounds = true;
theUIPathOptionslistBox.Focusable = true;
theUIPathOptionslistBox.Visibility = Visibility.Hidden;
theUIPathOptionslistBox.Height = 34;
theUIPathOptionsInnerStackPanel.Children.Add(theNewTextBox);
theUIPathOptionsInnerStackPanel.Children.Add(theUIPathOptionsButton);
theUIPathOuterStackPanel.Children.Add(theUIPathOptionsInnerStackPanel);
theUIPathOuterStackPanel.Children.Add(theUIPathOptionslistBox);
void button1_click(object sender, EventArgs e)
{
theUIPathOptionslistBox.Visibility = Visibility.Visible;
}
void button1_doubleclick(object sender, EventArgs e)
{
theNewTextBox.Text = theUIPathOptionslistBox.SelectedItem.ToString();
}
theUIPathOptionsButton.Click += button1_click;
theUIPathOptionslistBox.MouseDoubleClick += button1_doubleclick;
Grid.SetColumn(theUIPathOuterStackPanel, 4);
Grid.SetRow(theUIPathOuterStackPanel, nRow);
theDataGrid.Children.Add(theUIPathOuterStackPanel);
theEditControlList.Add(theNewTextBox);
}

This was (possibly) already answered here : Getting value of selected item in list box as string
string myItem = listBox1.GetItemText(listBox1.SelectedItem);
Then you just have to add your item to the textbox :
textBox1.Text = myItem;
If you don't want to create a new string variable, then this one is working too :
textBox1.Text = listBox1.SelectedItem.ToString();

ListBox, Item is a collection of objects, not strings, so you must let it know how to convert it to string, otherwise it will use its defualt .ToString() function that obviously the object currently in your items not giving the desired result.
Imagine items are oftype following class:
class SomeClass
{
public int Id;
public string Name;
}
You may do one of these three:
1.set the DisplayMember of your ListBox to Name
2.add override method to your class so that it overrides its .ToString() and return its Name property:
class SomeClass
{
public int Id;
public string Name;
public override string ToString()
{
return Name;
}
}
3.Just cast it to its real type and get the property you want:
SomeClass selected = (SomeClass)ListBox.SelectedItem;
TextBox1.Text = selected.Name;

This is because the TextBox will use the ToString() method on what it is bound to, which by default will return the class name.
You solutions are to either override the ToString() method of the class to return the value you want or set the text property of the TextBox to the text value you want rather then the object.

The solution I finally got to was as follows:
void theUIPathOptionslistBox_SelectedIndexChanged(object sender,
SelectionChangedEventArgs e)
{
theNewTextBox.Clear();
foreach (object selectedItem in theUIPathOptionslistBox.SelectedItems)
{
theNewTextBox.AppendText(selectedItem.ToString() + Environment.NewLine);
}
}
theUIPathOptionslistBox.SelectionChanged +=
theUIPathOptionslistBox_SelectedIndexChanged;

Related

Dynamic text boxes and using them

I've generated some textboxes and i want to the user input data in them after it added to form and then i use the data in them for some calculations.
how can i use the data?
TextBox t3 = new TextBox();
t3.Top = 222 + ((addalternativebutton - 3) * 60);
t3.Left = 214;
t3.Width = 76;
t3.Height = 22;
t3.Name = "txtwaste" + addalternativebutton.ToString();
this.tabore.Controls.Add(t3);
ww[addalternativebutton] = Convert.ToDouble(t3.Text);
As I mentioned in the comments you need to preserve the textbox instances which you are creating dynamically. You can either use generic dictionary, if you need to deal with the names assigned to them or you can use generic list.
Following solution I provide you which uses generic list.
First thing needed is a list which will preserve the textboxes.
public partial class Form1 : Form
{
private List<TextBox> textBoxes;
private int textBoxCount; //This is used to provide unique names to the
//textboxes and to track the number of dynamic textboxes.
public Form2()
{
InitializeComponent();
}
}
Now in click event of the button the textbox is created, positioned and added to the list as well as Form.Controls.
private void button1_Click(object sender, EventArgs e)
{
textBoxCount += 1;
TextBox t3 = new TextBox();
t3.Top = 20 + (22 * textBoxCount); //You can put your own logic to set the Top of textbox.
t3.Left = 120;
t3.Width = 50;
t3.Height = 20;
t3.Name = "txtwaste" + textBoxCount; //You can use your own logic of creating new name.
this.Controls.Add(t3);
this.textBoxes.Add(t3);
}
Now when you want to calculate the sum of the values of all the textboxes on click of another button.
private void button2_Click(object sender, EventArgs e)
{
double totalValue = 0;
foreach (var textBox in textBoxes)
{
double currentValue;
if (double.TryParse(textBox.Text, out currentValue))
{
totalValue += currentValue;
}
}
// Displaying totalValue in a label.
lblTotalValue.Text = "Total Value : " + totalValue;
}
This should help you resolve your issue.

Access a form object using variable parameters

Is there a way that I could access a label with variable parameters? For example, I have a list of labels (lbl00, lbl01, lbl02, lbl10, lbl11, lbl12) and need to be able to access them programmatically to change the background color. In the example below, strLabel = "lbl01", which would correspond to the correct object in my form, but this cannot be passed as a string. Is there any way I could make this work?
Thanks!
private void btnTest_Click(object sender, EventArgs e)
{
TestHilight("0", "1");
}
public void TestHilight(string x, string y)
{
String strLabel = "lbl" + x + y;
strLabel.BackColor = System.Drawing.Color.Green;
}
It is better if you keep track of your Labels in memory, but if you want to find a Label or a control based on Name then you can use Control.Find method:
var control = this.Controls.Find(strLabel, true); //pass "lbl" + x + y;
if(control != null && control.OfType<Label>().Any())
{
//label found
Label label = control.OfType<Label>().First() as Label;
label.BackColor = System.Drawing.Color.Green;
}
You can shorten your code like:
public void TestHilight(string x, string y)
{
var matchedLabel = Controls.Find("lbl" + x + y, true).OfType<Label>().FirstOrDefault();
if (matchedLabel != null)
{
//label found
matchedLabel.BackColor = System.Drawing.Color.Green;
}
}
You can either maintain a reference to label controls in a Dictionary where the key would be the string e.g. lbl01 and when you need to set the BackColor, find the corresponding label from the Dictionary and set its property.
Alternatively, you can search for the control by its name and set its BackColor property

Leaving the dropdown enabled

I want to disable a combobox, but at the same time I want to let the users see the other options available (that is, I want to enable the dropdown).
By default, when ComboBox.Enabled = false, the dropdown is also disabled (nothing happens when we click on the combobox).
My first thought is to leave it enabled and handle the ComboBox.SelectedIndex event to set it back to the default value (I will just need to gray it out in some way.)
I am wondering if there is any native functionality like this that I am missing, or if there would be other way of doing it.
Don't use a Combobox if you don't want the Combobox functionality. Use a ListView instead.
A "What You See Is What You Can't Get" Combobox seems a bad idea.
I suggest using ListBox instead.
It's a hacky workaround, but it should accomplish something similar to your request:
public partial class Form1 : Form
{
ComboBox _dummy;
public Form1()
{
InitializeComponent();
// set the style
comboBox1.DropDownStyle =
System.Windows.Forms.ComboBoxStyle.DropDownList;
// disable the combobox
comboBox1.Enabled = false;
// add the dummy combobox
_dummy = new ComboBox();
_dummy.Visible = false;
_dummy.Enabled = true;
_dummy.DropDownStyle = ComboBoxStyle.DropDownList;
this.Controls.Add(_dummy);
// add the event handler
MouseMove += Form1_MouseMove;
}
void Form1_MouseMove(object sender, MouseEventArgs e)
{
var child = this.GetChildAtPoint(e.Location);
if (child == comboBox1)
{
if (!comboBox1.Enabled)
{
// copy the items
_dummy.Items.Clear();
object[] items = new object[comboBox1.Items.Count];
comboBox1.Items.CopyTo(items, 0);
_dummy.Items.AddRange(items);
// set the size and position
_dummy.Left = comboBox1.Left;
_dummy.Top = comboBox1.Top;
_dummy.Height = comboBox1.Height;
_dummy.Width = comboBox1.Width;
// switch visibility
comboBox1.Visible = !(_dummy.Visible = true);
}
}
else if (child != _dummy)
{
// switch visibility
comboBox1.Visible = !(_dummy.Visible = false);
}
}
}
If using a ListBox as other answers suggested is not convenient. There is a way by creating a custom combobox and adding a ReadOnly property. Try this code :
class MyCombo : System.Windows.Forms.ComboBox
{
public bool ReadOnly { get; set; }
public int currentIndex;
public MyCombo()
{
currentIndex = SelectedIndex ;
}
protected override void OnSelectedIndexChanged(EventArgs e)
{
if (ReadOnly && Focused)
SelectedIndex = currentIndex;
currentIndex = SelectedIndex;
base.OnSelectedIndexChanged(e);
}
}
Usually the background color of read-only controls should not change, so I haven't done that part.

How can I to manipulate dynamically created controls?

Lets say I have a form where someone can catalog a multiple people's Name and their State and City?
Assume I already have all the State/Cities in database. (a table for each state, with cities listed in each table)
The Name field will be a TextBox. And the State & City fields will be ComboBox (DropDownLists).
One row (for the entry of one person) already exists in the form. But I want the user to be able to dynamically add rows of entries by pressing an "Add Person" button.
The next step is where I'm struggling. In each dynamically added row of fields, I would like the second ComboBox (Cities) to be populated depending on which State is chosen in the first Combo Box. Also, the Cities ComboBox will remain disabled until the State ComboBox is chosen.
My code looks something like this:
public ComboBox cbState;
public ComboBox cbCities;
public static int NumberOfPeople = 1;
private void btnAddNewPerson_Click(object sender, EventArgs e)
{
NumberOfPeople++;
TextBox txtPerson = new TextBox();
txtPerson.Name = "Person" + NumberOfPeople;
Panel.Controls.Add(txtPerson);
// ADD State ComboBox
cbState = new ComboBox();
cbState.Name = "State" + NumberOfPeople;
cbState.Enabled = true;
cbState.DropDownStyle = ComboBoxStyle.DropDownList;
Panel.Controls.Add(cbState);
// ADD City ComboBox
cbCity = new ComboBox();
cbCity.Name = "City" + NumberOfPeople;
cbCity.DropDownStyle = ComboBoxStyle.DropDownList;
cbCity.Enabled = false;
cbCity.SelectedValueChanged += new System.EventHandler(this.ChangeState);
Panel.Controls.Add(cbCity);
}
private void ChangeState(object sender, EventArgs e)
{
..... Don't know how to properly identify the City ComboBox that is in the same row as the State ComboBox that was just changed, and manipulate/populate it.....
}
Anyone able to help me solve this issue??
I'd greatly appreciate it!!
You could use a dictionary
Dictionary<ComboBox,ComboBox> CityToStateMap = new Dictionary<ComboBox,ComboBox>();
then when you add a row
CityToStateMap[cbState] = cbCity;
then when you changestate
ComboBox city = CityToStateMap[(ComboBox)sender];
First of all I would create an additional class (e.g. with name Row) that contains all controls of one row. So you can encapsulate controls of one person in one object.
Your Form class gets a list member of such row objects like
List<Row> _rows = new List<Row>();.
In constructor of that class Row you create the controls of one row and assign the event handlers to the SelectedValueChanged event of the combobox controls.
You could use the Control.Tag in order to attach a data object to your controls. See how the controls are introduced to each other in the example.
private void btnAddNewPerson_Click( object sender, EventArgs e )
{
AddPersonRow();
}
private void AddPersonRow()
{
// Create combo boxes
ComboBox cbCity = new ComboBox();
ComboBox cbState = new ComboBox();
// Introduce them to each other
cbCity.Tag = cbState;
cbState.Tag = cbCity;
// ADD State ComboBox
cbState.Name = "State" + NumberOfPeople;
cbState.Enabled = true;
cbState.DropDownStyle = ComboBoxStyle.DropDownList;
cbState.SelectedValueChanged += new EventHandler( cbState_SelectedValueChanged );
panel.Controls.Add( cbState );
// Populate the states sombo
PopulateStateCombo( cbState );
// ADD City ComboBox
cbCity.Name = "City" + NumberOfPeople;
cbCity.DropDownStyle = ComboBoxStyle.DropDownList;
cbCity.Enabled = false;
cbCity.SelectedValueChanged += new EventHandler(cbCity_SelectedValueChanged);
panel.Controls.Add( cbCity );
}
void cbState_SelectedValueChanged( object sender, EventArgs e )
{
ComboBox cbState = sender as ComboBox;
ComboBox cbCity = cbState.Tag as ComboBox;
cbCity.Enabled = true;
// .. Go ahead and populate cbCity by cbState's selected value ..
}
void cbCity_SelectedValueChanged( object sender, EventArgs e )
{
// Up to you...
}
Note that instead of shaking hands with each other ComboBox, you could create a class that will hold both ComboBoxes, your TextBox control, the row number, etc. and then set the Tag of all these controls to the class itself.
public class PersonRow
{
public int RowNum { get; private set; }
public TextBox NameTextBox { get; private set; }
public ComboBox CityCombo { get; private set; }
public ComboBox StateCombo { get; private set; }
public PersonRow( int rowNum )
{
RowNum = rowNum;
// Create the controls
NameTextBox = new TextBox();
CityCombo = new ComboBox();
StateCombo = new ComboBox();
// Bind them to this instance
NameTextBox.Tag = this;
CityCombo.Tag = this;
StateCombo.Tag = this;
//.. continue as in the prev. example..
}
}
First of all you should find the name of the comboBox you want to manipulate.
then you can search a control in the panel which has the name we just found, then you can do what ever you want.
here is the code for that
private void ChangeState(object sender,EventArgs e){
ComboBox stateComboBox= (ComboBox)sender;
//find the name of target City ComboBox
string cityComboName = "City"+stateComboBox.Name.Substring(5); // 5 is the Length of 'State'
ComboBox cityComboBox=null;
foreach(Control cntrl in panel1.Controls){
if (cntrl.Name == cityComboName) {
cityComboBox= (ComboBox)cntrl;
break;
}
}
if (cityComboBox!= null) {
cityComboBox.Enabled = true;
// now you have the both cityComboBox and stateComboBox Of the same Row
}
}

create custom object (combination of two objects)

hello creating a custom object may be a widely published topic, but my lack of coding skills proves problematic in actually implementing what i'm trying to do.
in a nutshell i'm adding controls at runtime in a flowpanelLayout. right now it's just listboxes, that code is all working fine. i would like a way to label the listboxes that are getting added, i can't think of a better way to do this than to use a text label. i was thinking it would be slick to create some sort of custom control (if possible) which is a listbox and a textlabel like one above the other or something. this way i can add the new custom control in my current code and assign the listbox attributes and label text, etc all in one motion.
this is what i was thinking, maybe there's even a better way to do this.
my current listview creation code:
public void addListView()
{
ListView newListView = new ListView();
newListView.AllowDrop = true;
newListView.DragDrop += listView_DragDrop;
newListView.DragEnter += listView_DragEnter;
newListView.MouseDoubleClick += listView_MouseDoubleClick;
newListView.MouseDown += listView_MouseDown;
newListView.DragOver += listView_DragOver;
newListView.Width = 200;
newListView.Height = 200;
newListView.View = View.Tile;
newListView.MultiSelect = false;
flowPanel.Controls.Add(newListView);
numWO++;
numberofWOLabel.Text = numWO.ToString();
}
maybe the actual best answer is simply to also add a textlabel here and define some set coordinates to put it. let me know what you think.
if a custom control is the way to go, please provide some resource or example for me - i'd appreciate it.
Here is a custom user control that can do that:
You just need to set TitleLabelText to set the title.
[Category("Custom User Controls")]
public class ListBoxWithTitle : ListBox
{
private Label titleLabel;
public ListBoxWithTitle()
{
this.SizeChanged +=new EventHandler(SizeSet);
this.LocationChanged +=new EventHandler(LocationSet);
this.ParentChanged += new EventHandler(ParentSet);
}
public string TitleLabelText
{
get;
set;
}
//Ensures the Size, Location and Parent have been set before adding text
bool isSizeSet = false;
bool isLocationSet = false;
bool isParentSet = false;
private void SizeSet(object sender, EventArgs e)
{
isSizeSet = true;
if (isSizeSet && isLocationSet && isParentSet)
{
PositionLabel();
}
}
private void LocationSet(object sender, EventArgs e)
{
isLocationSet = true;
if (isSizeSet && isLocationSet && isParentSet)
{
PositionLabel();
}
}
private void ParentSet(object sender, EventArgs e)
{
isParentSet = true;
if (isSizeSet && isLocationSet && isParentSet)
{
PositionLabel();
}
}
private void PositionLabel()
{
//Initializes text label
titleLabel = new Label();
//Positions the text 10 pixels below the Listbox.
titleLabel.Location = new Point(this.Location.X, this.Location.Y + this.Size.Height + 10);
titleLabel.AutoSize = true;
titleLabel.Text = TitleLabelText;
this.Parent.Controls.Add(titleLabel);
}
}
Example use:
public Form1()
{
InitializeComponent();
ListBoxWithTitle newitem = new ListBoxWithTitle();
newitem.Size = new Size(200, 200);
newitem.Location = new Point(20, 20);
newitem.TitleLabelText = "Test";
this.Controls.Add(newitem);
}

Categories