Using C# and WinForms, I can set a form to be localizable, put a label on it, and set text for the label in as many languages as I want. The text will be stored as string resources in one resource file for each language. Then, a user can select a language and all labels on the form will change to the correct language.
This does not seem to work for combo boxes. I can add items to a combo box for a localizable form and they will be stored in resource files using names such as ComboBox1.Item, ComboBox1.Item1, and ComboBox1.Item2, but the displayed text does not change when the combo box changes.
I've seen various suggestions for how to localize combo boxes, based on binding them to dictionaries or lists of tuples, but it seems to me that if items are stored in resource strings, there should be some more automatic way to use those resource strings. Is there?
Edit: Here is what should be a minimal example. A form has a text box, a button, a label and a combo box. The label and combo box each have resources for French (fr-FR) and Spanish (es-ES). The language name is entered in the text box, and the button changes the form's language using the following method:
private void ChangeLanguage(string lang)
{
ComponentResourceManager crm = new ComponentResourceManager(typeof(Form2));
CultureInfo culture = CultureInfo.CreateSpecificCulture(lang);
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
foreach (Control c in this.Controls)
{
crm.ApplyResources(c, c.Name, culture);
}
}
The result is that the label's text changes but the text of the combo box items does not.
If you close and reopen the form, everything will work fine. But if you would like to change the culture without closing the form, you need to add extra processing for ComboBox:
if (c is ComboBox)
{
var combo = (ComboBox)c;
var count = combo.Items.Count;
combo.Items.Clear();
combo.BeginUpdate();
for (int i = 0; i < count; i++)
{
var number = i == 0 ? "" : $"{i}";
var item = crm.GetString($"{c.Name}.Items{number}");
combo.Items.Add(item);
}
combo.EndUpdate();
}
crm.ApplyResources(c, c.Name);
Also keep in mind that your function is just applying the resource on the controls on the form and it's ignoring nested controls. For example, if some controls are hosted on a panel, it will ignore them. To fix this issue, take a look at this post.
Note:
In general , I recommend restarting the form to apply new language, because the custom logic is not limited to ComboBox, you need specific logic for ComboBox, ListBox, ListView, TreeView, DataGridView, ToolStrip, ContextMenuStrip, MenuStrip, StatusStrip and maybe smoe other controls which I forget to mention.
In short, I believe saving the selected culture in a setting and then Application.Restart() and applying culture in Main method is what you are looking for.
Related
I want to set the text in a combo box. Below is the code-
private System.Windows.Forms.ComboBox selectModel;
this.selectModel = new System.Windows.Forms.ComboBox();
this.selectModel.Name = "selectModel";
this.selectModel.FormattingEnabled = true;
this.selectModel.Size = new System.Drawing.Size(64, 21);
this.selectModel.Location = new System.Drawing.Point(3, 76);
this.selectModel.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
The following line is not working-
selectModel.SelectedText = getModelNameFromConf();
The documentation says that "it Gets or sets the text that is selected in the editable portion of a ComboBox". I can't make it editable to user.
Any workaround please.
This is because when you use ComboBoxStyle.DropDownList, the dropdown has no editable portion. To make it editable, use ComboBoxStyle.DropDown.
Note too the remarks on the SelectedText property relating to whether the control has focus. You may find the Text property more suitable for many purposes.
EDIT For example:
selectModel.Text = getModelNameFromConf();
Assuming the combo contains that value in its list, setting Text will also set the SelectedIndex property of the dropdown.
(I think some of the property names of this control are particularly confusing, including DropDown vs. DropDownList. Someone at MS had a bad day when this control was coded. Note also that the word selection is being used in two different ways: here, you want to set the selected item, whereas SelectedText means some text that is selected—which might not be the whole of the item text. This is the same as in a textbox where the user has dragged the mouse to highlight some of the text but not all of it.)
I have a user control which has a label and a text box. The text box gets the values dynamically at run time. There are n number of dynamic user controls added as shown below:
for loop
{
MyUserControl control = new MyUserControl();
control.SetLabelValue(label);
control.SetTextBoxValue(text);
flowLayoutPanel.Controls.Add(control);
}
flowLayoutPanel is my flow layout panel and SetLabelValue() and SetTextBoxValue() are methods in the user control class to add value to the controls. So lets say in the panel 10 such controls are added. Is there any way i can get the value(text) of all the text boxes which have been added?
Thanks
Use Linq. Substitute c.Text with whatever you use to get at the Value of one of your MyUserControls:
List<String> values = new List<String>();
foreach (MyUserControl c in flowLayoutPanel.Controls.OfType<MyUserControl>())
values.Add(c.Text);
Is there a way in C# to reference a control, in my case a TextBox, by using the value of a string variable? I am using the code below to make a single method that multiple control can use for the 'LostFocus' event. The sender TextBox then needs to calculate results based on the contents of other TextBoxes. The problem is that there are about 12 rows of TextBoxes, and while this code works to reuse the event method, I can't think of a way to reference the correct boxes that are not the sender. All of the boxes have similar names (ex - miCellSaturation, miCellRecords, orSaturation, orRecords), so my thinking was that if I can isolate part of the TextBox name with a Substring command, and then concatenate that with another string to form the complete TextBox name, this would work. I can do all that, but I don't know of a way to use the concatenated string to reference that box. Would this require iterating through all the boxes until it matches the correct name?
TextBox box = (TextBox)sender;
string boxName = box.Name;
if(boxName.EndsWith("Saturation"))
{
}
Not sure to understand you problem correctly, but if you need to find the references to a particular type of control with its name ending with a predefined string, then you could use
var list = YourForm.Controls.OfType<TextBox>()
.Where(x => x.Name.EndsWith("YourString"));
foreach(TextBox t in list)
{
Console.WriteLine(t.Name);
......
}
This could work only if your searched controls are directly included in the controls collection of the form. If these textboxes are included in some control container then you need to apply these lines to the appropriate control container instead of the form
I have a form which contains infinite number of options which user and add.
Some options are in textbox, and some are in combobox(selected is the value to be extracted).
The form is in a way that user can add as many combo box and text box he wants and let him write those information onto XML.
How do I code that in c#? If anyone can give me a short example of one each which loops through each added combo box and text box, that would be great.
Thank you in advance.
You can iterate through all controls inside a form like this.
foreach(Control control in this.Controls)
{
//here 'this' is representing the form you want to iterate through
//you can check whether it is a combobox or a text box
if(control.GetType() == typeof(Combobox))
{
//this is a combo box
}
else if(control.GetType() == typeof(Textbox))
{
//this is a text box
}
}
using above method you will find the controls inside a particular form. After that you can write information in a XML file
I'm writing an analyzer,which shows the packets of a specific program.Some packets are very large and the listview shows only the first 15-20 characters :\
This is my code
string __str = String.Join(" ", data.Select(x => x.ToString("x2")).ToArray()); //covert the byte[](packet) to hex string
string __ascii = AsciiToString(data); //convert the byte[](packet) to ASCII
if (encrypted) FormMain.PFA(form => form.listViewAnalyzer.Items.Add("S<-C [ENCRYPTED] Blowfishkey = 0xFF"));
else FormMain.PFA(form => form.listViewAnalyzer.Items.Add("S<-C"));
ListViewItem item = new ListViewItem(__str); //create new item and place the packet as hex string
item.SubItems.Add(__ascii); //add the ascii variant as substring
FormMain.PFA(form => form.listViewAnalyzer.Items.Add(item)); //add the item
It must be a property that prohibits adding text with more than x lines,but I can't see it.
The listview will contain all the text, you just can't see it if it's too long or has multiple lines.
The way that Outlook and things like packet sniffers often work is that the listview is accompanied by a textbox or "preview" window. You could change your UI so that selecting the item in the listview displays the full details of the item in an outlook-style preview pane. Then you could have a large multiline textbox and anything else you wanted. I often do this by putting an object in the ListViewItem.Tag property, so that I can retrieve it in the UI and display in the preview when the ListView.SelectedIndexChanged event fires.
Alternatively, the preview could be on a dialog that pops up when you double-click. In fact, make the preview UI a UserControl, then you can do both!
listview shows only the first 15-20 characters :\
Maybe you need to make the column wider?
It must be a property that prohibits adding text with more than x lines,but I can't see it.
List view items don't wrap text, so technically they prohibit text with more than 1 line