Xamarin Numeric only field - xamarin.ios

In my Xamarin forms View I have an entry control, to which I have added,
myEntry.Keyboard = Keyboard.Numeric;
to make it decimal only.
In Android devices this code will accept only one decimal point at any given time.
However in IOS, it accepts multiple decimal points?? Is there any way I can restrict only one decimal point in IOS too.

In Xamarin.Forms Entry you have a TextChanged event handler that you can tap into when the entry changes.
You are given both the old text string and also the new text string value.
You can then do a count on the number of decimal points that are in the new text string, check to see if it is greater than 1.
If it is, simply set the Entry.Text to the old value and then you will only ever have one decimal point.

Using the TextChanged event handler you can one of the various TryParse methods. These methods can be given specific cultures and styles also. Example below uses Double's version.
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
string newValue = e.NewTextValue;
double value;
if (double.TryParse(newValue, out value))
{
// Do logic for valid value
}
else
{
// Do logic for invalid value
}
}

Related

Stop formData string from being converted to a date string representation

This one is being hard to uncover. We have a .NET Core 2.2 app in which we have a form with many fields and a field for the user to attach some file.
Problem: one specific field CaqhNumber has a min and max length = 8.
When the user types in a value for example 20200706 the value that get's sent to the server is a date string representation of this value. So on the server side we get:
07/06/2020
Basically it thinks this specific field is an ISO date.
How can one stop this from happening? We just want to get the string on the server side the way it was entered on the UI side. It's not a date. It's plain string in both sides.
Something tells me this is related to the .NET Core configs.
Guess what... there was a piece of code behind the curtains messing up with the value:
const isValidDate = moment(
value,
moment.ISO_8601,
true
).isValid();
if (isValidDate) {
formData.append(
key,
moment(value).format('MM/DD/YYYY')
);
The fix:
if (value instanceof Date) {
formData.append(key, moment(value).format('MM/DD/YYYY'));

My segmented picker has normal Int values as tags, How is this passed to and from CoreData?

My SwiftUI segmented control picker uses plain Int ".tag(1)" etc values for its selection.
CoreData only has Int16, Int32 & Int64 options to choose from, and with any of those options it seems my picker selection and CoreData refuse to talk to each other.
How is this (??simple??) task achieved please?
I've tried every numeric based option within CoreData including Int16-64, doubles and floats, all of them break my code or simply just don't work.
Picker(selection: $addDogVM.gender, label: Text("Gender?")) {
Text("Boy ♂").tag(1)
Text("?").tag(2)
Text("Girl ♀").tag(3)
}
I expected any of the 3 CoreData Int options to work out of the box, and to be compatible with the (standard) Int used by the picker.
Each element of a segmented control is represented by an index of type Int, and this index therefore commences at 0.
So using your example of a segmented control with three segments (for example: Boy ♂, ?, Girl ♀), each segment is represented by three indexes 0, 1 & 2.
If the user selects the segmented control that represents Girl ♀, then...
segmentedControl.selectedSegmentIndex = 2
When storing a value using Core Data framework, that is to be represented as a segmented control index in the UI, I therefore always commence with 0.
Everything you read from this point onwards is programmer preference - that is and to be clear - there are a number of ways to achieve the same outcome and you should choose one that best suits you and your coding style. Note also that this can be confusing for a newcomer, so I would encourage patience. My only advice, keep things as simple as possible until you've tested and debugged and tested enough to understand the differences.
So to continue:
The Apple Documentation states that...
...on 64-bit platforms, Int is the same size as Int64.
So in the Core Data model editor (.xcdatamodeld file), I choose to apply an Integer 64 attribute type for any value that will be used as an Int in my code.
Also, somewhere, some time ago, I read that if there is no reason to use Integer 16 or Integer 32, then default to the use of Integer 64 in object model graph. (I assume Integer 16 or Integer 32 are kept for backward compatibility.) If I find that reference I'll link it here.
I could write about the use of scalar attribute types here and manually writing your managed object subclass/es by selecting in the attribute inspector Class Codegen = Manual/None, but honestly I have decided such added detail will only complicate matters.
So your "automatically generated by Core Data" managed object subclass/es (NSManagedObject) will use the optional NSNumber? wrapper...
You will therefore need to convert your persisted/saved data in your code.
I do this in two places... when I access the data and when I persist the data.
(Noting I assume your entity is of type Dog and an instance exists of dog i.e. let dog = Dog())
// access
tempGender = dog.gender as? Int
// save
dog.gender = tempGender as NSNumber?
In between, I use a "temp" var property of type Int to work with the segmented control.
// temporary property to use with segmented control
private var tempGender: Int?
UPDATE
I do the last part a little differently now...
Rather than convert the data in code, I made a simple extension to my managed object subclass to execute the conversion. So rather than accessing the Core Data attribute directly and manipulating the data in code, now I instead use this convenience var.
extension Dog {
var genderAsInt: Int {
get {
guard let gender = self.gender else { return 0 }
return Int(truncating: gender)
}
set {
self.gender = NSNumber(value: newValue)
}
}
}
Your picker code...
Picker(selection: $addDogVM.genderAsInt, label: Text("Gender?")) {
Text("Boy ♂").tag(0)
Text("?").tag(1)
Text("Girl ♀").tag(2)
}
Any questions, ask in the comments.

CLLocation does not have a Coordinates property

I am just working my way through the location services for the first time and everything appears to be working in that it correctly finds my location but I am having trouble extracting the coordinates.
The docs states that CLLocation has a "Coordinates" property and the compiler is happy with this piece of code. However at runtime the CLLocation only appears to return a string description.
I start the location manager
_locationManager = new CLLocationManager ();
_locationManager.DesiredAccuracy = 1000;
// handle the updated location method and update the UI
_locationManager.LocationsUpdated += (object sender, CLLocationsUpdatedEventArgs e) => {
UpdateLocation (e.Locations [e.Locations.Length - 1], _destinationLatitude, _destinationLongitude);
};
if (CLLocationManager.LocationServicesEnabled)
_locationManager.StartUpdatingLocation ();
The event fires correctly
static public void UpdateLocation (CLLocation current, Double destinationLat, Double destinationLng)
{
//Make the start pairing
string start = current.Coordinate.Latitude.ToString() + "," + current.Coordinate.Longitude.ToString();
//Make the destination pairing
string destination = destinationLat.ToString() + "," + destinationLng.ToString();
}
However the app just crashes out. Catching it on a breakpoint I see the following which only appears to have a description property that contains.
Description "<+50.58198902,-3.67661728> +/- 65.00m (speed -1.00 mps / course -1.00) # 25/07/2013 13:11:28 British…" string
I can obviously extract the lat/lng from this text field but I get the feeling I shouldn't need to do this. Any help appreciated.
I moved the exact same code into a different controller and it worked fine. The only difference between the two controllers was that the failing controller was using the monotouch dialog reflection api to bind the screen elements. I can't see why this would make any difference but it is the only difference between the two controllers. Everything is working now, I will try to reproduce in a smaller sample if I get the time.

UltraNumericEditor allows values larger than MaxValue setting

Using infragistics UltraNumericEditor, if I set the .MaxValue to 50, the control will allow me to enter decimals larger than the limit (for example, 50.99)
I see the same behavior if I set the .MaxValue property to 50.01 (can set values larger)
I can obviously resolve this in code but resetting the value, but it seems like the control should do this on its own.
Is there something I'm missing in how to use these properties correctly?
I suppose you are using the UltraNumericEditor with the property Style set to Decimal (or Double).
In this case the control allows you to insert digits that render the input invalid with respect to the property MaxValue. However, by default, you are not able to exit the control until the value is correct.
If you want, you can use the event ValidationError that gives your the ValidationErrorEventArgs parameter. This parameter contains the LastValidValue property to reset the wrong value, the RetainFocus to let your user exit from the editor (or, if you prefer, display an error message)
private void ultraNumericEditor1_ValidationError(object sender, ValidationErrorEventArgs e)
{
// Reset the content to the last valid value and allow the exit from the editor
ultraNumericEditor1.Value = e.LastValidValue;
e.RetainFocus = false;
// In alternative display a message, but leave the wrong value to be reedited
// DisplayValidationMessage("The max value allowed is 50.00");
}
The problem was a result of the IEditorDataFilter for percentage values.
Infragistics recommends, and I had implemented, an IEditorDataFilter which converts decimal percentages (.5 = 50%) into percentages for display.
This filter is applied before the validation for the control takes place. Therefore, setting the MaxValue to "50" allowed me to enter "50.99" but not "51"... normally this would have caused a validation error as per Steve's answer. However, because of the IEditorDataFilter applied to this control, the value was automatically converted to .5099 and this new value does not violate the constraint.
The solution I implemented was to check the value in the Validated event to see if it was larger than the MaxValue / 100, and if so to set it equal to the same.

get back to lower level j2me

I have a textfield (lower level) a call a function that call a higher level form that contains a datafield to pick up a date and display it in my textfield lowerlevel.
The problem is I cannot get back to my textfield (lower level) since the datefield appears
public void formdatepicker() {
final javax.microedition.lcdui.Command CONFIRM_COMMAND
= new javax.microedition.lcdui.Command("OK",
javax.microedition.lcdui.Command.OK, 1);
javax.microedition.lcdui.Command CANCEL_COMMAND
= new javax.microedition.lcdui.Command("Cancel",
javax.microedition.lcdui.Command.CANCEL, 2);
final DateField datefield = new DateField("Pick a date", DateField.DATE);
form.append(datefield);
form.addCommand(CONFIRM_COMMAND);
form.addCommand(CANCEL_COMMAND);
form.setCommandListener(new CommandListener() {
public void commandAction(javax.microedition.lcdui.Command c, Displayable d) {
if (c == CONFIRM_COMMAND) {
Date date = datefield.getDate();
display.setCurrent(null);// try to hide the current form to get
}
}
});
Display.getInstance().getJ2MEDisplay().setCurrent(form);
Your mistake is wrong assumption about what setCurrent(null) does. Per your question and code snippet, it looks like you expect it to somehow show the screen that has been displayed prior to form. It doesn't, see the exaplanation in the API javadocs (available online):
The application may pass null as the argument to setCurrent(). This does not have the effect of setting the current Displayable to null; instead, the current Displayable remains unchanged. However, the application management software may interpret this call as a request from the application that it is requesting to be placed into the background...
If you want to use setCurrent(Displayable) to show some screen instead of current one, you need to pass this screen as an argument to setCurrent.
For the sake of completeness, note that there is another version of setCurrent that accepts two parameters, first of which is Alert, which works a bit differently, but it is not applicable in your case because you use Form not Alert.

Resources