Entry's are showing default text instead of showing placeholder Xamarin - c#

When I run the app, on first up page instead Entrys are showing default text 0 instead of placeholder.
I have AddContactPage.xaml
<StackLayout>
<Entry Placeholder="Enter Class" Text="{Binding Class}"></Entry>
<Entry Placeholder="Enter Id" Text="{Binding StudentId}"></Entry>
</StackLayout>
Attributes binded to Entries
public int StudentId { get; set; }
public int Class { get; set; }
How can I solve this issue. See o/p-

Actually you can use StringFormat. Try this
StringFormat='{0:#.##;;}'

One possible solution is a string property for binding:
private int _studentId;
public int StudentId
{
get { return _studentId; }
set
{
SetProperty(ref _studentId, value);
RaisePropertyChanged("StudentIdString"); // If you're using Prism. You can use any other way to raise the PropertyChanged event
}
}
public string StudentIdString
{
get { return StudentId.ToString(); }
}
That's it! Now you can bind StudentIdString to your Entry. Do the same with Class and you're good to go.
Another solution to your problem is a converter as Woj suggested:
public class IntToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int i = (int)value;
return i.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return int.Parse((string)value);
}
}
Then use it in your xaml like this:
<ContentPage.Resources>
<ResourceDictionary>
<local:IntToStringConverter x:Key="intToString" />
</ResourceDictionary>
</ContentPage.Resources>
<Entry Placeholder="Enter Id" Text="{Binding StudentId, Converter={StaticResource intToString}}"></Entry>

Since the Entry control Text is binded to a model, it will not show a place holder for a null property which is associated. You may need to remove the Text binding in that case.

Related

Xamarin Persistent color chooser

I make a button and Color picker to xamarin.forms app, but I want to make it when I choose one color (ex. red) and close app, when i reopen it to see this red color automatic picked. I try to use this code but Preferences not working with Color:
public Color ColorPicker
{
get => Preferences.Get(nameof(ColorPicker), color.Red);
set
{
Preferences.Set(nameof(ColorPicker), value);
OnPropertyChanged(nameof(ColorPicker));
}
}
Can someone help me?
You can store Xamarin.Forms.Color as a string like this:
public string ColorPicker
{
get => Preferences.Get(nameof(ColorPicker), Color.Red.ToString());
set
{
Preferences.Set(nameof(ColorPicker), value);
OnPropertyChanged(nameof(ColorPicker));
}
}
Then you can bind it for instance to Label like this:
<Label TextColor="{Binding ColorPicker}" />
Make sure you set BindingContext in your view. You can read more about Binding here.
The Color.FromHex(string value) method needs a string type parameter. Try to convert the value to string type in the custom class.
Check the code:
Custom Converter class
public class StringToColorConverter : IValueConverter, INotifyPropertyChanged
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var color = Color.FromHex(value as string);
return color;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Page.xaml
<ContentPage.Resources>
<local:StringToColorConverter x:Key="myConverter" />
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout BackgroundColor="{Binding Color_string, Converter={StaticResource myConverter}}">
...
</StackLayout>
</ContentPage.Content>
I is not possible to make it like this. Because i need to use converter after to make string=>color. I am trying this:
public class StringToColor : IValueConverter
{
ColorTypeConverter converter = new ColorTypeConverter();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//return value.ToString(); //not working
//return (Color)(converter.ConvertFromInvariantString(value.ToString())); //not working
return Color.FromHex(value.ToString()); //not working too
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
and add this convetor to xaml
<ContentPage.Resources>
<ResourceDictionary>
<local:StringToColor x:Key="str" />
</ResourceDictionary>
</ContentPage.Resources>
<Label Text="TEST" FontSize="Title" TextColor="{Binding ColorPicker,
Converter={StaticResource str}}"/>
but nothing happend...

How to simplify bindings that depend on each other?

I have an Entry that I want to give a red outline when the entry is empty. I'm using SyncFusion's SFTextInputLayout for my Entry and it has a property "HasError" that once it's set to true, it'll automatically highlight my entire in Red.
Here is the following XAML code for SFTextInputLayout
<inputLayout:SfTextInputLayout Grid.Column="0" Hint="Phone Number" ContainerType="{StaticResource RepairOrderContainerType}" HasError="{Binding IsPhoneNumberError}" FocusedColor="{StaticResource AccentColor}" VerticalOptions="Center" HorizontalOptions="Start">
<Entry Keyboard="Telephone" Style="{StaticResource TextInputStyle}" Text="{Binding PhoneNumber}"/>
</inputLayout:SfTextInputLayout>
As you can see, I have two bindings that handles the text of the entry and another one to check if it has an error or not. While this solution works, it will get redundant pretty soon as the number of my entry fields grow. For every entry field I have, I need another boolean to cover its Error property as shown below.
private string _phoneNumber;
public string PhoneNumber
{
get => _phoneNumber;
set
{
IsPhoneNumberError = string.IsNullOrWhiteSpace(value) ? true : false;
this.RaiseAndSetIfChanged(ref _phoneNumber, _phoneNumber);
}
}
private bool _isPhoneNumberError = false;
public bool IsPhoneNumberError
{
get => _isPhoneNumberError;
set
{
this.RaiseAndSetIfChanged(ref _isPhoneNumberError, value);
}
}
I'm wondering if there's any way to simplify this code. Thanks in advance!
One way of many to accomplish this is by creating a custom control with a behavior.
create a custom control:
public class MySfTextInputLayout : SfTextInputLayout
{
public MySfTextInputLayout ()
{
Behaviors.Add(new ShowErrorBehavior());
}
public bool HasErrors
{
get { return (bool)GetValue(HasErrorsProperty); }
set { SetValue(HasErrorsProperty, value); }
}
public static readonly BindableProperty HasErrorsProperty =
BindableProperty.Create(nameof(HasErrors), typeof(bool), typeof(MySfTextInputLayout ), false);
}
and the behavior:
public class ShowErrorBehavior : Behavior<MySfTextInputLayout>
{
protected override void OnAttachedTo(MySfTextInputLayout entry)
{
entry.TextChanged += OnEntryTextChanged;
base.OnAttachedTo(entry);
}
protected override void OnDetachingFrom(MySfTextInputLayout entry)
{
entry.TextChanged -= OnEntryTextChanged;
base.OnDetachingFrom(entry);
}
void OnEntryTextChanged(object sender, TextChangedEventArgs args)
{
((MySfTextInputLayout)sender).HasErrors = string.IsNullOrWhiteSpace(args.NewTextValue);
}
}
The behavior will decide the validity of text for you, so you don't have to bind to another property just for that.
Also take a look at the Validation API, you may want to add multiple rules for an entry to be valid:
https://devblogs.microsoft.com/xamarin/validation-xamarin-forms-enterprise-apps/
You can achieve requirement to handle error when adding multiple entry fields by binding entry text to HasError property and using Converter as shown in below code snippets.
Code snippets [Xaml]:
<StackLayout >
<inputLayout:SfTextInputLayout
Grid.Column="0"
HasError="{Binding Text,Source={x:Reference entry1}, Converter={StaticResource Converter}}"
Hint="Phone Number"
HorizontalOptions="Start"
VerticalOptions="Center">
<Entry x:Name="entry1" Keyboard="Telephone" Text="{Binding PhoneNumber}" />
</inputLayout:SfTextInputLayout>
<inputLayout:SfTextInputLayout
Grid.Column="0"
HasError="{Binding Text,Source={x:Reference entry2}, Converter={StaticResource Converter}}"
Hint="Address"
HorizontalOptions="Start"
VerticalOptions="Center">
<Entry x:Name="entry2" Text="{Binding Address}" />
</inputLayout:SfTextInputLayout>
</StackLayout>
Code snippets [C#]:
public class Converter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
return string.IsNullOrEmpty(value.ToString()) ? true : false;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
Sample: https://www.syncfusion.com/downloads/support/directtrac/general/ze/TextInputLayout-1703941642.zip

Xamarin: Get bound property of Entry.Text from event handler in code behind

Very simplified version of my code:
ViewModels:
public class ViewModel
{
public ObjectViewModel {get; set;}
}
public class ObjectViewModel
{
public string MyString {get; set;}
public bool MyStringIsValid {get; set;}
}
Xaml:
<Entry Text="{Binding ObjectViewModel.MyString}" TextChanged="Entry_TextChanged"/>
<Label Text="Valid!" IsVisible="{Binding ObjectViewModel.MyStringIsValid}"/>
In my code behind, I would like to be able to grab the bound property of Entry.Text by doing something like this:
void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
//Psuedocode
//ObjectViewModel ovm = (sender as Entry).Text.Binding.Source;
}
The reason I want to do this is to perform validation on "MyString" and change its "MyStringIsValid" property if necessary. My question is how do I do this and if it isn't possible, can you recommend a better approach?
In my real code I have used INotifyPropertyChanged to update the view according to viewModel changes, but I have omitted this for brevity.
Thanks!
I guess all you need is a Converter. I don't know why you need to maintain a property for changing the IsVisible based on the validation of a text. The below code works for me for a similar scenario which you mentioned.
<!--Declare the namespace at the top of the XAML-->
xmlns:c="clr-namespace:Demo.Helper"
<!--Register your Converter in the Resources-->
<ContentPage.Resources>
<ResourceDictionary>
<c:TextToBoolConverter x:Key="textToSpeechConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<Entry x:Name="entry1" Text="{Binding ObjectViewModel.MyString}" />
<Label Text="Valid!" IsVisible="{Binding Text, Source={x:Reference entry1}, Converter={StaticResource textToSpeechConverter}}"/>
Below is the converter code which I tested.
public class TextToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string stringValue = value?.ToString();
if (!string.IsNullOrEmpty(stringValue))
return true;
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

Xamarin Forms Xaml Converter: Bindable property

In Xamarin Forms I'm trying to create a xaml converter with properties.
This is to be used, for example, to show values from a list in different ways, based on a code behind property.
I based my code on this: https://stackoverflow.com/a/29869734.
Converter:
namespace App2.Converters
{
class MyConverter : IValueConverter
{
public int ConvParam { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return $"value: {value} - ConvParam: {ConvParam}";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
XAML:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:conv="clr-namespace:App2.Converters"
x:Class="App2.MainPage"
x:Name="MainPageXaml">
<ContentPage.Resources>
<conv:MyConverter x:Key="cnv" ConvParam="{Binding Source={Reference MainPageXaml}, Path=PropParam}" />
<!--<conv:MyConverter x:Key="cnv" ConvParam="333" />-->
</ContentPage.Resources>
<StackLayout Orientation="Vertical">
<!-- Place new controls here -->
<Label Text="{Binding Source={Reference MainPageXaml}, Path=PropVal}" />
<Label Text="{Binding Source={Reference MainPageXaml}, Path=PropParam}" />
<Label Text="{Binding Source={Reference MainPageXaml}, Path=PropVal, Converter={StaticResource cnv}}" />
</StackLayout>
Code behind:
public partial class MainPage : ContentPage
{
public int PropVal { get; set; } = 111;
public int PropParam { get; set; } = 222;
public MainPage()
{
InitializeComponent();
}
}
The goal is to bind ConvParam of my converter to PropParam in code behind.
But if I use:
<conv:MyConverter x:Key="cnv" ConvParam="{Binding Source={Reference MainPageXaml}, Path=PropParam}" />
the error Position 10:39. No property, bindable property, or event found for 'ConvParam', or mismatching type between value and property is shown and the app doesn't compile.
The property ConvParam itself is recognized inside xaml: if I replace the above line with
<conv:MyConverter x:Key="cnv" ConvParam="333" />
everything works.
The binding expression I used ({Binding Source={Reference MainPageXaml}, Path=PropParam}) actually works, if used as source for the text property of a label:
<Label Text="{Binding Source={Reference MainPageXaml}, Path=PropParam}" />
But if I use it in Resources, It doesn't work.
Thanks to Julipan I could make it work!
As he pointed out, ConvParam must be a BindableProperty, so I modified my converter to inherit from BindableObject and defined ConvParam as BindableProperty.
Converter:
namespace App2.Converters
{
class MyConverter : BindableObject, IValueConverter
{
public static readonly BindableProperty ConvParamProperty = BindableProperty.Create(nameof(ConvParam), typeof(int), typeof(MyConverter));
public int ConvParam
{
get { return (int)GetValue(ConvParamProperty); }
set { SetValue(ConvParamProperty, value); }
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return $"value: {value} - ConvParam: {ConvParam}";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Binding two Strings (Concatenation) in an image Xamarin.Forms

Am having a scenario , where i have a BaseImageUrl String
private const string BaseImageUrl = "http://eamobiledirectory.com/cooperp/Images/app_images/";
for the images i want to retrieve into the Image view in Xaml plus concatenating it with a string value office_photo which has the exact image name forexample flower.jpg and is got after deserializing JSON and it comes as a List , below is my Model class :
public class Adverts
{
public string office_photo { get; set; }
public DateTime entryDate { get; set; }
}
so what i want is how to concatenate the BaseUrl and office_photo in XAML so that i get the complete link to images .
below is my Image in the ListView :
<ListView x:Name="listViewTest" HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Image Aspect="AspectFill" Source="{Binding office_photo}" x:Name="advertImage"
WidthRequest="200"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Just concatenate the two strings in a new property in your view modem and bind to that property. It's really simple and one line of code :-)
Something like this:
public string PhotoUrl { get { return BaseImageUrl + office_photo; }}
Use a IValueConverter
Something like
public class AddBaseUrlConverter : IValueConverter
{
#region IValueConverter implementation
private const string BaseImageUrl = "http://eamobiledirectory.com/cooperp/Images/app_images/";
public object Convert (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string && ! string.IsNullOrEmpty((string)value)) {
return string.Format("{0}{1}", BaseImageUrl, (string)value);
}
return ""; //
}
public object ConvertBack (object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException ();
}
#endregion
}
Then in your XAML something like
<ContentPage.Resources>
<ResourceDictionary>
< AddBaseUrlConverter x:Key="cnvInvert"></AddBaseUrlConverter >
</ResourceDictionary>
</ContentPage.Resources>
<Image Aspect="AspectFill" Source="{Binding office_photo, Converter={StaticResource cnvInvert}}" x:Name="advertImage" WidthRequest="200"/>
(not tested, but it could work)

Categories