currently I am facing the following problem.
In my application (which is a plugin for AutoCAD/BricksCAD), i am using a DataGrid with a custom Column, that ensures the input to be in a float-format.
The code for the column looks something like that:
public class DataGridFloatColumn : DataGridTextColumn
{
protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
{
TextBox edit = editingElement as TextBox;
edit.PreviewTextInput += OnPreviewTextInput;
return base.PrepareCellForEdit(editingElement, editingEventArgs);
}
void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
string txt = ((TextBox)sender).Text + e.Text;
float _;
e.Handled = !float.TryParse(txt, out _);
}
}
This part works as expected. I am only allowed to input float numbers, separated by a comma. The problem however is, that the DataGrid expects a dot as decimal separator.
Due to this, initial values are represented with a dot, and If I type something with a comma, it simply gets removed when hitting enter... for example 123,4 --> 1234
What I have already tried:
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("de-DE");
System.Threading.Thread.CurrentThread.CurrentUICulture = new System.Globalization.CultureInfo("de-DE");
But when printing Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator, i am getting a comma...
Any suggestions?
Thank you ind advance!
I dont know if it covers your issue, but if I want culture-specific number/datetime formatting in XAML, I put this "hack" into the constructor of my "App.xaml.cs"
public App()
{
FrameworkElement.LanguageProperty.OverrideMetadata(
typeof(FrameworkElement),
new FrameworkPropertyMetadata(XmlLanguage.GetLanguage("de-DE")));
}
Thread.CurrentThread.CurrentCulture = myCulture somehow does not do the trick.
Related
I've been struggling with the Samsung Galaxy numeric keyboard decimal separator nightmare.
I have an Entry on which I must only accept numeric values (including decimals), so in my xaml code I wrote <Entry Keyboard="Numeric"/> and it worked just fine on the VS19 android simulator. But when I run the app on my physical device (Samsung Galaxy S10+) the comma key is disabled and the .- key doesn't work (it types nothing).
I made some digging online and found a few solutions, but none worked for me.
SOLUTION 1
Forcing the app culture to pt-BR (because my phone system language is brazilian portuguese) by adding this code to App() (in App.xaml.cs):
private void SetCultureToPTBR()
{
CultureInfo br = new CultureInfo("pt-BR");
CultureInfo.DefaultThreadCurrentCulture = br;
}
But there were no changes.
SOLUTION 2
Setting input type on a custom renderer for entries:
[assembly: ExportRenderer(typeof(Entry), typeof(CustomEntryRenderer))]
namespace AppCoperNitro.Droid.CustomRenderers
{
public class CustomEntryRenderer : EntryRenderer
{
public CustomEntryRenderer(Context context) : base(context)
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if (Control == null || e.NewElement == null)
return;
this.Control.KeyListener = DigitsKeyListener.GetInstance(true, true);
this.Control.InputType = Android.Text.InputTypes.ClassNumber | Android.Text.InputTypes.NumberFlagDecimal;
}
}
}
This method changed the .- key to a comma key, and it kinda works (it types a .), but the decimal place is ignored (if I type 2.3 the app receives it as 23).
SOLUTION 3
This solution, but the result was the same as solution 2.
I also tried combining these solutions and their variances, but nothing works the way it should. I don't even care if the entry shows a comma or a dot, I just need the decimal number to be received correctly.
We can change the ways. According to your SOLUTION 2, the entry can input the ., so you can do something in the Entry's UnFocused event. Such as: // Use Gabic's code
private void Entry_Unfocused(object sender, FocusEventArgs e)
{
Entry entry = sender as Entry;
if (entry.Text.Length > 0 && Android.OS.Build.Manufacturer.Equals("Samsung", StringComparison.CurrentCultureIgnoreCase))
{
string a = entry.Text.Replace('.', ',');
entry.Text = a;
}
}
And then add the event into the xaml:
<Entry Keyboard="Numeric" Unfocused="Entry_Unfocused"/>
I have a DropDown (using MahApps if that is important) that I'd like to use to switch the language "on the fly" in my program.
Language Class
namespace SAM
{
public class Language
{
public string Title { get; set; }
public string Culture { get; set; }
}
}
Change Language
private void DropLanguage_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
Language lang = DropLanguage.SelectedItem as Language;
System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang.Culture);
}
I have all my strings as resources in Resources.resx (default) and Resources.en.resx (english)
3 issues I don't understand
When selecting "englisch" from the dropdown, the language does not change immediately but when I click sth. else, e.g. "close" (it asks "sure?"), the language has changed.
Strings that are directly in the .xaml file like <TextBlock Text="{x:Static p:Resources.Config_HeaderBar_Find_Speaker}" /> do not get updated at all.
Bonus: How would I switch back to the default language, as new CultureInfo(lang.Culture); expects one parameter and for the default I have Culture = null (as the Resources.resx has nothing in it's name). Changing the file to Resources.default.resx messes with my code a lot...
I tried to solve similar problem. The simplest solution for me was to move all Window content to UserControl and creating interface for window with method refreshLanguage(). Then I call from model:
private void SetLanguage(string cultureName)
{
var cul = new System.Globalization.CultureInfo(cultureName);
Properties.Resources.Culture = cul;
System.Globalization.CultureInfo.DefaultThreadCurrentCulture = cul;
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = cul;
System.Threading.Thread.CurrentThread.CurrentUICulture = cul;
System.Threading.Thread.CurrentThread.CurrentCulture = cul;
InitializeHamburgerMenu();
MainWindowView.RegreshLanguage();
RaisePropertyChanged("Title");
}
And RefreshLanguage in Window looks like:
public void RegreshLanguage()
{
GlobalUserControl content = new GlobalUserControl("Views/SettingsPage.xaml");
ContentPresenter_GlobalUserControl.Content = content;
}
In my case, UserControl provides navigation, so I passed last navigated URI as parameter. So, if you need to preserve state you can pass it as parameter to new UserControl. Recreating usercontrol cause all strings to reload without window recreation. Maybe good idea would be to call GC.Collect(); here, but depends on your scenario.
About default neutral culture. For me works to call SetLanguage("").
There are 2 things
Thread.CurrentThread.CurrentCulture
and
Thread.CurrentThread.CurrentUICulture
In order to set these valuse use the static method
CultureInfo.GetCultureInfo(String langCode)
where some examples of the parameter langCode are the following strings
"de-DE"
"en-US"
etc.
more info at
https://msdn.microsoft.com/en-us/library/yck8b540(v=vs.110).aspx
So, overall these lines of code sould work for change in German Language:
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("de-DE");
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("de-DE");
OK, so I am trying to apply the accounting number format for all textboxes on my Form.
Now, I did some research here and found this post that will help me to set the format.
And then I found another post to apply the format for all textbox controls on the form without adding the format code individually to all controls.
Well, the thing is that the code on the format uses the control name, which will bind it to a single textbox control. I tried the control name (TextoBox) instead, and it also failed.
There is another issue to consider, that even if I manage to get past the above problem, the code from format is an event, named after the control name, so I do not think it will work if I apply it to a class or method and call for it.
While I already do have the solution to what I want, I would like to know if there is a faster way to apply it, which will not add so much lines to my code. Trying to learn how to keep things easier to read, doing less with more. Any advise?
Thanks for reading.
It sounds like you have all the pieces, just need help putting it together. For the ControlName, you can cast the sender object to the control and access its Name property.
void SetProperty(Control ctr)
{
foreach (Control control in ctr.Controls)
{
if (control is TextBox)
{
control.Leave += control_Leave;
}
else
{
if (control.HasChildren)
{
SetProperty(control);
}
}
}
}
void control_Leave(object sender, EventArgs e)
{
var textBox = sender as TextBox;
Double value;
if (Double.TryParse(textBox.Text, out value))
textBox.Text = String.Format(System.Globalization.CultureInfo.CurrentCulture, "{0:C2}", value);
else
textBox.Text = String.Empty;
}
Usage:
SetProperty(this);
Also, from my comment on the OP: If accounting is truly important, I would suggest using the Decimal type instead of Double. Double will be faster, but Decimal is more precise. Figure out which trade off makes sense and make a decision based on that.
Edit per comments:
myTextBox.Leave -= control_Leave
If you know the name of the control, the above will work. You will need to do this after you use SetProperty(this). If you want to handle this inside the SetProperty() method, do a check on control.Name == "myTextBox".
You can subscribe multiple controls event(that use the same args) to the same event handler :
public YourFormConstructor()
{
foreach(var textbox in form.Controls.OfType<TextBox>())
textbox.Leave += FormatCurrencyText;
}
private void FormatCurrencyText(object sender, EventArgs e)
{
var textbox = sender as TextBox;
Double value;
if (Double.TryParse(textbox.Text, out value))
textbox.Text = String.Format(System.Globalization.CultureInfo.CurrentCulture, "{0:C2}", value);
else
textbox.Text = String.Empty;
}
Currently i set Y axis of my chart using N2 format like this
chart.ChartAreas[0].AxisY.LabelStyle.Format = "{0:N2}";
What i want to achieve is that N2 is using Indonesian format, i know how to do it in object conversion just like below
sum.ToString("N2", CultureInfo.GetCultureInfo("id-ID"));
How to apply CultureInfo in formatting chart axis?
You can use the FormatNumber event of the chart.
private readonly CultureInfo indonesiaCulture = CultureInfo.GetCultureInfo("id-ID");
void chart1_FormatNumber(object sender, FormatNumberEventArgs e)
{
if (e.ElementType == ChartElementType.AxisLabels)
{
e.LocalizedValue = e.Value.ToString("N2", indonesiaCulture);
}
}
Or you can change the Thread.CurrentUICulture for the UI thread and set LabelStyle.Format property. I've not tested it, I believe that should also work.
In addition to Sriram Sakthivel's answer.
You can use Format property this way:
chart.ChartAreas[0].AxisY.LabelStyle.Format = "IndonesianNumericFormat";
void chart_FormatNumber(object sender, FormatNumberEventArgs e)
{
switch (e.Format)
{
case "IndonesianNumericFormat":
e.LocalizedValue = e.Value.ToString("N2", new CultureInfo("id-ID"));
break;
}
}
So, you can set different formats to different columns and incapsulate logic of string conversion to a class \ factory etc.
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: