winform localization to arabic and change the alignment - c#

I have project and it supports 4 languages but now customer wants one more language. It is Arabic. I have no idea how to display Arabic in Labels and TextBoxes.
I know Arabic is written from right to left and its starting point is the right side of the label ord textview.
here is my sample code. this code show english,german and arabic....
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
if (comboBox1.SelectedItem.ToString().Equals("en-GB"))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-GB");
label1.Text= FormLabels.test1;
label2.Text = FormLabels.test2;
}
else if (comboBox1.SelectedItem.ToString().Equals("de-DE"))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
label1.Text = FormLabels.test1;
label2.Text = FormLabels.test2;
}
else if (comboBox1.SelectedItem.ToString().Equals("ar"))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("ar");
label1.Text = FormLabels.test1;
label2.Text = FormLabels.test2;
}
}
How am I supposed to display Arabic characters and display the test from right to left?

//...
else if (comboBox1.SelectedItem.ToString().Equals("ar"))
{
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("ar");
label1.RightToLeft = label2.RightToLeft = RightToLeft.Yes;
label1.Text = FormLabels.test1;
label2.Text = FormLabels.test2;
}
UPDATE
if you have many many labels, there are some solutions here:
You can define a class such as called RighToLeftLabel and use it to declare all your labels:
public class RightToLeftLabel : Label {
public RightToLeftLabel(){
RightToLeft = RightToLeft.Yes;
}
}
//Then declare your labels:
RightToLeftLabel label1 = new RightToLeftLabel();
RightToLeftLabel label2 = new RightToLeftLabel();
RightToLeftLabel label3 = new RightToLeftLabel();
//you can also drag-n-drop this custom Label from the ToolBox (remember to place the class in your project namespace and build first, after that you will see there is a RightToLeftLabel control at the very top in the ToolBox)
You can loop though the collection of your Labels and change RightToLeft to Yes for each one:
foreach(Label lbl in yourLabels)
lbl.RightToLeft = RightToLeft.Yes;
//I think this is right for you because the project language may change...

i want to add on kingKing answer, which is excellent as always, that you should consider making all the form RightToLeft, because when you read the form you can't read the form RightToLeft and have the control in a reverse way.
here is an example of what i mean: if it was an arabic form translated to english:

Related

TextBox in WPF and text format

Im trying to create a TextBox control and force user to enter only numbers in specyfic format there.
How can I do it in WPF?
I have not found any properties like "TextFormat" or "Format" in TextBox class.
I made TextBox like this (not in visual editor):
TextBox textBox = new TextBox();
I want TextBox behavior like in MS Access forms, (user can put only numbers in that textbox in "000.0" format for example).
Consider using WPF's built in validation techniques. See this MSDN documentation on the ValidationRule class, and this how-to.
What you probably need is a masked input. WPF doesn't have one, so you can either implement it yourself (by using validation, for example), or use one of available third-party controls:
FilteredTextBox from WPFDeveloperTools
MaskedTextBox from Extended WPF Toolkit
etc.
Based on your clarification, you want to limit user input to be a number with decimal points.
You also mentioned you are creating the TextBox programmatically.
Use the TextBox.PreviewTextInput event to determine the type of characters and validate the string inside the TextBox, and then use e.Handled to cancel the user input where appropriate.
This will do the trick:
public MainWindow()
{
InitializeComponent();
TextBox textBox = new TextBox();
textBox.PreviewTextInput += TextBox_PreviewTextInput;
this.SomeCanvas.Children.Add(textBox);
}
Meat and potatoes that does the validation:
void TextBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
// change this for more decimal places after the period
const int maxDecimalLength = 2;
// Let's first make sure the new letter is not illegal
char newChar = char.Parse(e.Text);
if (newChar != '.' && !Char.IsNumber(newChar))
{
e.Handled = true;
return;
}
// combine TextBox current Text with the new character being added
// and split by the period
string text = (sender as TextBox).Text + e.Text;
string[] textParts = text.Split(new char[] { '.' });
// If more than one period, the number is invalid
if (textParts.Length > 2) e.Handled = true;
// validate if period has more than two digits after it
if (textParts.Length == 2 && textParts[1].Length > maxDecimalLength) e.Handled = true;
}

how to add more labels according to the later input?

I don't know whether it is clear. I mean a form has an input textbox and a button. If I input 5 in the textbox and click on the button, the form will add 5 labels...
The question is I don't know it is 5 or 4 or 3……before the code is running and the input.
I don't know how to add the labels and how to define or get their names in order to use them later in the code.
I am just learning windows applications development with VS using C#....
And also this is my first ask in stackoverflow please forgive me if it is not clear. Is there anybody can help me?
let's split your entire problem into few steps of understanding:
What basically down the line, you are asking, is to how to add controls dynamically in a winform, in your case the control is label, so wrap your label creating logic in a function like below:
protected Label CreateLabel(string Id, string text)
{
Label lbl = new Label();
lbl.Name = Id;
lbl.Text = text;
return lbl;
}
Now you need to add as many labels as the number entered in a given textBox and upon a button click, so possibly something like below in button's click event:
protected void button_Clicked(object sender, EventArgs e)
{
//make sure nothing invalid string comes here
int counter = Convert.ToInt32(txtCount.text);
for(int i=0;i<counter;i++)
{
var lbl = CreateLabel("rand"+i, "Label" +i);
container.Controls.Add(lbl);//container can be your form
}
}
Now the basic problem in winforms you will face, will be about the positioning of these dynamically added labels. The most simple way to go about it is to add your labels to winforms FlowLayoutPanel. It automatically aligns the controls. There are other layout controls available aswell. so do this :
drag and drop a FlowLayoutPanel on your form and give it the name "container", rest assured
For example:
for(var i=0; i<N; i++ ) {
var l= new Label();
l.Text = "some name #" + i.ToString();
l.Width = 200;
l.Location = new Point(30, 20);
parent.Controls.Add(l);
}
You can use this as:
Label[] arrLabel;
int num = 0;
int.TryParse(textBox1.Text, out num);
arrLabel = new Label[num];
for (int i = 0; i < num; i++)
{
arrLabel[i] = new Label();
arrLabel[i].Text = "Label #" + (i+1);
arrLabel[i].Width = 20;
arrLabel[i].Location = new Point(30+10*(i+1), 20);
this.Controls.Add(arrLabel[i]);
}

Label without Padding and Margin

I have the following code in C# (.NET Framework 3.5)
public partial class MainForm : Form
{
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
Label myControl = new Label();
myControl.Text = "TEXT";
myControl.FlatStyle = FlatStyle.System;
myControl.AutoSize = true;
myControl.BorderStyle = BorderStyle.FixedSingle;
myControl.Padding = new Padding(0);
myControl.Margin = new Padding(0);
this.Controls.Add(myControl);
InitializeComponent();
}
}
Which should display a label with the text enclose by a border, like this:
------
|TEXT|
------
Instead, I get this:
--------
|TEXT |
--------
And I don't know why... My objective is to be able to have multiple labels without space between them, like this:
-----------
|TEXT|TEXT|
-----------
Am I missing something? Thanks in advance!
For clarification, I need to have NO SPACE between the text and the border.
This is what solved it for me (using #LarsTech's solution):
I added
protected override void OnHandleCreated(EventArgs e) {
base.OnHandleCreated(e);
this.AutoSize = false;
}
protected override void OnFontChanged(EventArgs e) {
base.OnFontChanged(e);
this.Size = GetTextSize();
}
protected override void OnResize(EventArgs e) {
base.OnResize(e);
this.Size = GetTextSize();
}
protected override void OnTextChanged(EventArgs e) {
base.OnTextChanged(e);
this.Size = GetTextSize();
}
private Size GetTextSize() {
Size padSize = TextRenderer.MeasureText(".", this.Font);
Size textSize = TextRenderer.MeasureText(this.Text + ".", this.Font);
return new Size(textSize.Width - padSize.Width, textSize.Height);
}
to my label definition.
I also added
textLabel.FlatStyle = FlatStyle.System;
Thank you very much for the help!
I don't know what's going on with the FlatStyle property, except to say that FlatStyle.System has a similar effect on my system. The other FlatStyle values indicate clearly what the effect will be on the control, but FlatStyle.System is pretty nebulous.
The appearance of the control is determined by the user's operating system.
I'm not sure what in the OS plays a role in the layout of he control. LarsTech's comment about changing it to FlatStyle.Standard (or any other value for that matter) fixes the issue for me (and doesn't trim off any text, as your comment indicates is happening to you).
You can override the alignment behavior by explicitly setting it to the center:
myControl.TextAlign = ContentAlignment.MiddleCenter;
I'm not sure exactly what you're trying to achieve (since it seems you could just enter all of your text in a single Label, not multiple next to each other), but you may also want to remove the border style:
myControl.BorderStyle = BorderStyle.None;
And, similar to what Blablablaster said, consider using a FlowLayoutPanel and adding your Label controls to that. You can place the above code in a loop, adding each one to the panel, and it'll take care of laying them out next to each other for you.
for (var i = 0; i < 10; i++)
{
Label myControl = new Label();
myControl.Text = "TEXT";
...
...
flowLayoutPanel1.Controls.Add(myControl);
}

Why can't I leave a TextBox using tab?

I have this code:
public static void AddDefaultTextFromTag(params TextBox[] textBoxes)
{
foreach (TextBox oTextBox in textBoxes)
{
bool isPasswordChar = oTextBox.UseSystemPasswordChar;
oTextBox.Enter += (sndr, evnt) =>
{
if (((TextBox)sndr).Text == ((TextBox)sndr).Tag.ToString())
{
((TextBox)sndr).Text = "";
((TextBox)sndr).UseSystemPasswordChar = isPasswordChar;
((TextBox)sndr).ForeColor = SystemColors.WindowText;
}
};
oTextBox.Leave += (sndr, evnt) =>
{
if (((TextBox)sndr).Text.Trim().Count() == 0)
{
((TextBox)sndr).UseSystemPasswordChar = false;
((TextBox)sndr).CharacterCasing = CharacterCasing.Normal;
((TextBox)sndr).Text = ((TextBox)sndr).Tag.ToString();
((TextBox)sndr).ForeColor = SystemColors.GrayText;
}
};
if (oTextBox.Text.Trim().Count() == 0)
{
oTextBox.UseSystemPasswordChar = false;
oTextBox.CharacterCasing = CharacterCasing.Normal;
oTextBox.Text = oTextBox.Tag.ToString();
oTextBox.ForeColor = SystemColors.GrayText;
}
}
}
But when the TextBox.UseSystemPasswordChar I input in this method's parameter is true and it's TextBox.Text property is empty, the TextBox can't leave using a Tab button on the keyboard, only a MouseClick can be used to lose the focus of that TextBox.
Why is this happening?
My code is in C#, framework 4, build in VS2010 Pro, project is in WinForms.
I use a TextBox from the VS ToolBox.
Please help. Thanks in advance.
The reason you can't leave the textbox is because you are changing the CharacterCasing property in the textbox.
Not sure why it works like this, but it has happened to me before, what I ended up doing was capture the keypress event, and if it was a letter I'd switch it to it's uppercase value. It's not optimal, but it works
I did something similar to this (writing it from the top of my head, but it should work):
void YourTextbox_KeyPress(object sender, KeyPressEventArgs e)
{
if (char.IsLetter(e.KeyChar))
{
if (this.CharacterCasing == CharacterCasing.Upper && char.IsLower(e.KeyChar))
{
this.Text = this.Text.Insert(this.SelectionStart, char.ToUpper(e.KeyChar) + string.Empty);
this.SelectionStart++;
e.Handled = true;
}
else if (this.CharacterCasing == System.Windows.Forms.CharacterCasing.Lower && char.IsUpper(e.KeyChar))
{
this.Text = this.Text.Insert(this.SelectionStart, char.ToLower(e.KeyChar) + string.Empty);
this.SelectionStart++;
e.Handled = true;
}
}
}
You also should use the new keyword to "override" (I know that's not the right term here) the Character casing, so it doesn't do it's own thing
public new CharacterCasing CharacterCasing { get; set; }
The code basically checks if the pressed key is a letter, then, if it's marked as Upper, and the char is lower, replaces it with it's upper version (in the position of the cursor) then moves the cursor to the next part, and Viceversa (toLower)
NOTE:
This code will have may (should) have some trouble if the user has more than one character selected (SelectionLenght > 0), if you want to keep the normal Textbox functionality, you should delete all the selected characters
So I set up a WinForms app, drew two textboxes, set one to UseSystemPasswordChar=true then set it up like so:
private void Form1_Load(object sender, EventArgs e)
{
textBox2.Tag = "test2";
textBox1.Tag = "test1";
TextBox[] tb = { textBox1, textBox2 };
AddDefaultTextFromTag(tb);
}
Your function works fine and I have no problems tabbing through the controls on the form no matter what the textboxes contain. (added a button also that does nothing for tabbing test) so... no repro unless my test setup is not valid
What I found in the answer of this post was the solution for me. Instead of setting UseSystemPasswordChar to true and then to false, you can set PasswordChar to '●' and then to '\0' to have normal text. You should not set the UseSystemPasswordChar because it has precedence over PasswordChar.

Using dynamically created controls in C#

I am creating an application where a user will input grades and the program will output the weighted average. On load, it will ask for the number of categories for the assignments. The program will then dynamically create textboxes for the user to input information. The problem is that I can not figure out how to read the text that is inputed after I create the textboxes. Here is my code:
TextBox txtbx = new TextBox();
txtbx.Text = "";
txtbx.Name = "txtbx1";
txtbx.Location = new Point(10, 10);
txtbx.Height = 20;
txtbx.Width = 50;
Controls.Add(txtbx);
How can I change this code so I can find the current text in the box when the user submits?
If you are dynamically generating controls then obviously you won't be able to have a field for each one. But if you are trying to access the Controls collection for a named control, the ControlCollection can be indexed by name. After adding the text box with the specified name, you can simply do:
TextBox txtbx = (TextBox)Controls["txtbx1"];
You could use the FindControl method of the Page class.
This method takes a parameter which is the TextBox's ID, which you have to set upon creation:
txtbx.ID = "txtbx1";
Then you can select it:
TextBox txtbx1 = (TextBox)FindControl("txtbx1");
and use it.
Edit: Since the initial question added that he is refering to Windows Forms, my reply above is off-topic.
In Windows Forms, you should simply use a class member variable instead of a local variable. E.g.:
public partial class MyForm
{
...
private TextBox txtbx;
...
private void createControls()
{
txtbx = new TextBox();
txtbx.Text = "";
txtbx.Name = "txtbx1";
txtbx.Location = new Point(10, 10);
txtbx.Height = 20;
txtbx.Width = 50;
Controls.Add(txtbx);
}
private void someOtherFunction()
{
// Do something other with the created text box.
txtbx.Text = "abc";
}
}
This code for the Dynamically Add Textbox On Button Click
int count = 1;
public System.Windows.Forms.TextBox AddNewTextBox()
{
System.Windows.Forms.TextBox txt = new System.Windows.Forms.TextBox();
this.Controls.Add(txt);
txt.Top = count * 25;
txt.Left = 100;
txt.Text = "TextBox " + this.count.ToString();
count = count + 1;
return txt;
}
private void Onbutton_Click(object sender, EventArgs e)
{
//Call the method AddNewTextBox that uses for Dynamically create Textbox
AddNewTextBox();
}
I hope this code will help you .
Thank You
Happy Coding:)
Keep a list of references of all text boxes on the form. Add the textBox reference to the list when you create them dynamically.
Then you can simply iterate through all text boxes in the list when you want to read their text.
Make sure that you name the text boxes as per their related category names. Then you can also Find the control in the list by their names.
class MyForm : Form
{
IList<TextBox> _textBoxes = new List<TextBox>();
private void AddTextBox(string categoryName){
var myTextBox = new TextBox();
myTextBox .Name = categoryName + "txtbx";
// set other properties and add to Form.Controls collection
_textBoxes.Add(myTextBox);
}
private TextBox FindTextBox(string categoryName)
{
return _textBoxes.Where( t => t.Name.StartsWith(categoryName)).FirstOrDefault();
}
}
All you need to do is set up an OnClick listener for your submit button and have it do something like this
private void OnSubmit(object sender, EventArgs args)
{
string yourText = txtbx.Text;
}
You'll have to keep a reference to the text box after you create it. yourText will contain the value you need. Hope this helps

Categories

Resources