How autoclear a EntryCell in Xamarin.Forms? - xamarin

I have a EntryCell that need to AutoClear each time the user select it. I know how do that on iOS directly but not with Xamarin.Forms.

If you mean clear the value when the Entry is Focused this can be accomplished in a few ways.
The easy way: Handling the Focused event.
<Entry Placeholder="Name" HorizontalOptions="FillAndExpand" Focused="Handle_Focused" />
and in code behind
void Handle_Focused(object sender, Xamarin.Forms.FocusEventArgs e)
{
((Entry)sender).Text = string.Empty;
}
note that you could also use ((Entry)sender).ClearValue(Entry.TextProperty); inside your Handle_Focused method.
Or with the still easy and cleaner way: Using a Behavior
namespace YourRootNamespace.Behaviors
{
public class EntryClearOnFocusBehavior : Behavior<Entry>
{
protected override void OnAttachedTo(Entry bindable)
{
if (bindable == null)
{
throw new InvalidOperationException("Entry was null. Behavior can only be atached to an Entry");
}
bindable.Focused += OnEntryFocused;
base.OnAttachedTo(bindable);
}
protected override void OnDetachingFrom(Entry bindable)
{
bindable.Focused -= OnEntryFocused;
base.OnDetachingFrom(bindable);
}
void OnEntryFocused(object sender, FocusEventArgs e)
{
((Entry)sender).ClearValue(Entry.TextProperty);
}
}
}
Then in your XAML you would:
Add this namespace in your ContentPage definition xmlns:behaviors="clr-namespace:YourRootNamespace.Behaviors"
and attach the behavior to your Entry (or Entries).
<Entry Placeholder="Last Name" HorizontalOptions="FillAndExpand">
<Entry.Behaviors>
<behaviors:EntryClearOnFocusBehavior />
</Entry.Behaviors>
</Entry>
This way is my favorite as it gives you reusability.
You can go one step further and create a Style with this Behavior so attaching the behavior would be as simple as adding an style. More about this here.
Hopes this helps.-

You can use trigger, It is very simple solution
<Entry Placeholder="enter name">
<Entry.Triggers>
<Trigger TargetType="Entry"
Property="IsFocused" Value="True">
<Setter
Property="Text"
Value="" />
</Trigger>
</Entry.Triggers>
</Entry>
For EntryCell:
XAML code
<ListView x:Name="listView" SeparatorVisibility="None" ItemsSource="{x:Static local:HomeViewModel.lights}">
<ListView.ItemTemplate>
<DataTemplate>
<EntryCell Label="{Binding comment}" Text="{Binding name}" Tapped="Item_Tapped" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code behind
void Item_Tapped(object sender, System.EventArgs e)
{
((EntryCell)sender).Text = "";
}

Related

How to fix this exception:Cannot convert a NSColorType.Catalog color without specifying the color space, use the overload to specify an NSColorSpace

I am trying to build a Xamarin.Forms 5 MacOS project - the XAML is the basic as provided by the default boiler plate code.
When I compile the project I get an exception:
The exception:
Cannot convert a NSColorType.Catalog color without specifying the color space, use the overload to specify an NSColorSpace
As I said, I have not added any custom code yet. How do I fix this?
Update
If I downgrade to Xamarin Form 4.8 it builds and runs with no exception:
So why is 5.x failing?
XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="VisitsRota.MainPage">
<StackLayout>
<Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
<Label Text="Welcome to Xamarin.Forms!" HorizontalTextAlignment="Center" TextColor="White" FontSize="36"/>
</Frame>
<Label Text="Start developing now" FontSize="Title" Padding="30,10,30,10"/>
<Label Text="Make changes to your XAML file and save to see your UI update in the running app with XAML Hot Reload. Give it a try!" FontSize="16" Padding="30,0,30,0"/>
<Label FontSize="16" Padding="30,24,30,0">
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="Learn more at "/>
<Span Text="https://aka.ms/xamarin-quickstart" FontAttributes="Bold"/>
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
</StackLayout>
</ContentPage>
AppDelegate
using AppKit;
using Foundation;
using VisitsRota;
using Xamarin.Forms;
using Xamarin.Forms.Platform.MacOS;
namespace VisitsRota.MacOS
{
[Register("AppDelegate")]
public class AppDelegate : FormsApplicationDelegate
{
NSWindow window;
public AppDelegate()
{
var style = NSWindowStyle.Closable | NSWindowStyle.Resizable | NSWindowStyle.Titled;
var rect = new CoreGraphics.CGRect(200, 1000, 1024, 768);
window = new NSWindow(rect, style, NSBackingStore.Buffered, false);
window.Title = "Visits Rota for Mac";
window.TitleVisibility = NSWindowTitleVisibility.Hidden;
}
public override NSWindow MainWindow
{
get { return window; }
}
public override void DidFinishLaunching(NSNotification notification)
{
Forms.Init();
LoadApplication(new App());
base.DidFinishLaunching(notification);
}
}
}
The exception is on base.DidFinishLaunching(notification); I think.
Updating to latest Xamarin.Forms resolved this issue.

Outlined Textbox in Xamarin.Forms

I want to implement material outlined textbox in Xamarin.Forms. I had created custom renderers but not able to apply style to it.
I want text box like this image https://i.stack.imgur.com/7pWPr.png
By creating custom renderer and inheriting from TextInputLayout displays default material textbox.
https://i.stack.imgur.com/Ek9Vb.jpg
You can use Custom Renderer to custom a View which contained a material designed Entry .
Create a EntryView in Forms:
public class EntryView : ContentView
{
public static readonly BindableProperty TextProperty =
BindableProperty.Create("Text", typeof(string), typeof(EntryView), null);
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
Second , you need to create the EntryViewRenderer in Android :
public class EntryViewRenderer : ViewRenderer
{
global::Android.Views.View view;
global::Android.Widget.EditText editText;
EntryView entryView;
Activity activity;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.View> e)
{
base.OnElementChanged(e);
if(e.NewElement != null)
{
entryView= e.NewElement as EntryView;
}
if (e.OldElement != null || Element == null)
{
return;
}
try
{
SetupUserInterface();
SetupEventHandlers();
AddView(view);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(#" ERROR: ", ex.Message);
}
}
private void SetupEventHandlers()
{
editText.TextChanged += EditText_TextChanged;
}
private void EditText_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
entryView.Text = editText.Text;
Console.WriteLine("chanegd +" + entryView.Text);
}
void SetupUserInterface()
{
activity = this.Context as Activity;
view = activity.LayoutInflater.Inflate(Resource.Layout.EntryLayout, this, false);
editText = view.FindViewById<EditText>(Resource.Id.editText1);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
{
base.OnLayout(changed, l, t, r, b);
var msw = MeasureSpec.MakeMeasureSpec(r - l, MeasureSpecMode.Exactly);
var msh = MeasureSpec.MakeMeasureSpec(b - t, MeasureSpecMode.Exactly);
view.Measure(msw, msh);
view.Layout(0, 0, r - l, b - t);
}
}
In addition , you need to add EntryLayout for this View :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/Widget.MaterialComponents.TextInputLayout.OutlinedBox">
<EditText
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Label"
android:outlineSpotShadowColor="#color/cardview_shadow_start_color"/>
</android.support.design.widget.TextInputLayout>
</LinearLayout>
Now , you can use it in Xaml of Xamarin Forms :
xmlns:app18="clr-namespace:App18"
<app18:EntryView Text="abc"/>
The effect :
If need to modify color of outline , just add style in Resources/values/styles.xml .
<style name="LoginTextInputLayoutStyle" parent="Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense">
<item name="boxStrokeColor">#570dff</item>
<item name="boxStrokeWidth">2dp</item>
<item name="android:textColorHint">#570dff</item>
</style>
In Resources/values/colors.xml add follow code :
<color name="mtrl_textinput_default_box_stroke_color">#570dff</color>
Finally used in EntryLayout.xml :
<android.support.design.widget.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="#style/LoginTextInputLayoutStyle">
<EditText
android:id="#+id/editText1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Label"/>
</android.support.design.widget.TextInputLayout>
The efect:
You can achieve using Grid with some -ve margin value like this:
<Grid>
<Frame Padding="10"
BorderColor="#570dff"
HasShadow="False">
<Entry Placeholder="Enter here"/>
</Frame>
<Label Text=" UserName "
FontSize="15"
TextColor="#570dff"
BackgroundColor="white"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="20,-10,0,0"/>
</Grid>
Output:
<Grid Margin="20">
<Frame Padding="10"
BorderColor="#570dff"
HasShadow="False">
<Entry Placeholder="Enter here"/>
</Frame>
<Label Text=" UserName "
FontSize="15"
TextColor="#570dff"
BackgroundColor="white"
HorizontalOptions="Start"
VerticalOptions="Start"
Margin="20,-10,0,0"/>
</Grid>
This is great, it also helped me. I added a Margin of 20 to the grid to make it look better.

How can I create a template / class that will allow me to simplify some my Xaml where there are multiple elements into just one?

Here's an example of what I need to do now. Sometimes I have one span, sometimes more.
Note that this post is similar to that of another question. For the other question I had only one comment to use a custom control with no more advice offered and one answer to use JavaScript. I tried to add a second bounty to that question but it gave me the option of only adding a bounty of 500 points. The question is now so old that I doubt anyone will see it any more and as I cannot add a bounty (unless it's 500 points) I cannot give it more visibility.
Here's what I would like to simplify:
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="Hello " />
<Span Text="Hello " />
<Span Text=" Some more text." />
</FormattedString>
</Label.FormattedText>
</Label>
Here's what I would like to do instead of typing in <Label><Label.FormattedText><FormattedString> I would like to get some way to do this with only entering in <template:FormattedLabel>
<template:FormattedLabel>
<Span Text="Hello " />
<Span Text="Hello " />
<Span Text=" Some more text." />
</template:FormattedLabel>
or
<template:FormattedLabel>
<Span Text="Hello " />
</template:FormattedLabel>
Note that I have looked into custom controls but as far as I see I cannot find a way to make these accept some inside content which in this case would be one or more spans.
I have an example of something similar which could perhaps be used but I am not sure how to apply it. What I was hoping for was a template like this in the XAML below which is does something similar to what I need but for content pages:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=J"
xmlns:t="clr-namespace:J.Templates"
x:Class="Japanese.Templates.ContentScrollable"
x:Name="ContentPage" >
<ContentPage.Content>
<t:Stack Orientation="Vertical">
<ScrollView x:Name="scroll">
<ContentView Content="{Binding Source={x:Reference ContentPage}, Path=InnerContent}"
Margin="{DynamicResource PageMargin}" />
</ScrollView>
</t:Stack>
</ContentPage.Content>
</ContentPage>
With its C# back end:
public partial class ContentScrollable : ContentPage
{
public static readonly BindableProperty InnerContentProperty = BindableProperty.Create(nameof(InnerContent), typeof(View), typeof(ContentScrollable));
public View InnerContent
{
get => (View)this.GetValue(InnerContentProperty);
set => this.SetValue(InnerContentProperty, value);
}
public ContentScrollable()
{
InitializeComponent();
}
}
How can I accomplish what I am looking for?
You can do the following:
<!-- FormattedLabel.xaml -->
<?xml version="1.0" encoding="UTF-8"?>
<Label
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="YourNamespaceForTemplates.FormattedLabel" />
// FormattedLabel.xaml.cs
[ContentProperty(nameof(Spans))]
public partial class FormattedLabel : Label
{
private readonly ObservableCollection<Span> _spans;
public IList<Span> Spans => _spans;
public FormattedLabel()
{
_spans = new ObservableCollection<Span>();
_spans.CollectionChanged += OnSpansChanged;
InitializeComponent();
}
private void OnSpansChanged(object sender, NotifyCollectionChangedEventArgs e)
{
FormattedText?.Spans?.Clear();
FormattedText = FormattedText ?? new FormattedString();
Spans.ForEach(FormattedText.Spans.Add);
}
}
Basically, in this extension of Label we define the content to be a list of Span items, which will allow you to define them in XAML inside <FormattedLabel></FormattedLabel>. To make it work, we pass these items down to this.FormattedText.Spans.
To use it:
<template:FormattedLabel>
<Span Text="Hello " />
<Span Text="Hello " />
<Span Text=" Some more text." />
</template:FormattedLabel>
I have just checked it and it works perfectly. I hope this helps!

Can a template simplify the adding of one or more spans in FormattedString in FormattedText to Labels?

Here's an example of what I need to do now. Sometimes I have one span, sometimes more.
<Label>
<Label.FormattedText>
<FormattedString>
<Span Text="Hello " />
<Span Text="Hello " />
<Span Text=" Some more text." />
</FormattedString>
</Label.FormattedText>
</Label>
Is there any way that this could be accomplished with a template so the XAML needed was more like this:
<template:FormattedLabel>
<Span Text="Hello " />
<Span Text="Hello " />
<Span Text=" Some more text." />
</template:FormattedLabel>
or
<template:FormattedLabel>
<Span Text="Hello " />
</template:FormattedLabel>
Note that I have looked into custom controls but as far as I see I cannot find a way to make these accept some inside content which in this case would be one or more spans.
What I was hoping for was a template like this which is what I used for content pages:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Japanese;assembly=J"
xmlns:t="clr-namespace:J.Templates"
x:Class="Japanese.Templates.ContentScrollable"
x:Name="ContentPage" >
<ContentPage.Content>
<t:Stack Orientation="Vertical">
<ScrollView x:Name="scroll">
<ContentView Content="{Binding Source={x:Reference ContentPage}, Path=InnerContent}"
Margin="{DynamicResource PageMargin}" />
</ScrollView>
</t:Stack>
</ContentPage.Content>
</ContentPage>
With its back end in C#
public partial class ContentScrollable : ContentPage
{
public static readonly BindableProperty InnerContentProperty = BindableProperty.Create(nameof(InnerContent), typeof(View), typeof(ContentScrollable));
public View InnerContent
{
get => (View)this.GetValue(InnerContentProperty);
set => this.SetValue(InnerContentProperty, value);
}
public ContentScrollable()
{
InitializeComponent();
}
}
Does anyone have any ideas how I can accomplish what I am looking for?
Using Javascript you can add or remove spans on the go
FormattedStrings could also be defined via code
const label = new Label();
const firstLabelSpan = new Span();
firstLabelSpan.text = "Formatted String ";
const secondLabelSpan = new Span();
secondLabelSpan.text = "Label";
const formattedStringLabel = new FormattedString();
formattedStringLabel.spans.push(firstLabelSpan);
formattedStringLabel.spans.push(secondLabelSpan);
label.formattedText = formattedStringLabel;
programmatically you can push or pop spans and manage labels

Custom Renderer: Custom Renderer for rounded buttons

I am developing a cross-platform app using PCL Xamarin Forms Project. My app will run on ios, android, windows 10 and windows 8.1 desktops.
I want to make a custom renderer for button control in xamarin forms in which I can specify following properties from xaml page and from code behind also-
Border Color
Border Width
Border Radius
Background Color
Text Color
Text font size, color, attribute like bold.
Height and Width of Button
I have tried the normal button control of xamarin forms but in that border radius does not work in android and on hover button color changes in windows 10.
So how can I achieve this?
I using these properties on my app and for me works fine.
I am using these properties with "Styles".
Example:
<Style x:Key="buttonStyle" TargetType="Button">
<Setter Property="BackgroundColor" Value="{DynamicResource Snow}"/>
<Setter Property="TextColor" Value="{DynamicResource LightBlue}" />
<Setter Property="BorderColor" Value="{DynamicResource LightBlue}"/>
<Setter Property="BorderRadius" Value="15"/>
<Setter Property="BorderWidth" Value="1"/>
<Setter Property="FontAttributes" Value="Bold" />
</Style>
My Button:
<Button Text="Login" Command="{Binding LoginCommand}" Style="{DynamicResource buttonStyle}" />
Xamarin Styles
In Android the RadiusProperty stops working only with AppCompat its a known issue
AppCompat
If you want to use a normal button and AppCompat at the same time you will need to inherit from Button and register a CustomRenderer.
[assembly: ExportRenderer(typeof(RoundButton), typeof(RoundButtonRenderer))]
namespace Project.Droid.Renderers
{
public class RoundButtonRenderer : Xamarin.Forms.Platform.Android.AppCompat.ButtonRenderer
{
ButtonDrawable _backgroundDrawable;
Drawable _defaultDrawable;
bool _drawableEnabled;
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (_backgroundDrawable != null)
{
_backgroundDrawable.Dispose();
_backgroundDrawable = null;
}
}
base.Dispose(disposing);
}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
{
base.OnElementChanged(e);
if (e.OldElement != null && _drawableEnabled)
{
_drawableEnabled = false;
_backgroundDrawable.Reset();
_backgroundDrawable = null;
}
UpdateDrawable();
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (_drawableEnabled &&
(e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || e.PropertyName == Xamarin.Forms.Button.BorderColorProperty.PropertyName || e.PropertyName == Xamarin.Forms.Button.BorderRadiusProperty.PropertyName ||
e.PropertyName == Xamarin.Forms.Button.BorderWidthProperty.PropertyName))
{
_backgroundDrawable.Reset();
Control.Invalidate();
}
base.OnElementPropertyChanged(sender, e);
}
private void UpdateDrawable()
{
if (Element.BackgroundColor == Color.Default)
{
if (!_drawableEnabled)
return;
if (_defaultDrawable != null)
Control.SetBackground(_defaultDrawable);
_drawableEnabled = false;
}
else
{
if (_backgroundDrawable == null)
_backgroundDrawable = new ButtonDrawable();
_backgroundDrawable.Button = Element;
if (_drawableEnabled)
return;
if (_defaultDrawable == null)
_defaultDrawable = Control.Background;
Control.SetBackground(_backgroundDrawable.GetDrawable());
_drawableEnabled = true;
}
Control.Invalidate();
}
}
public class ButtonDrawable : IDisposable
{
object _backgroundDrawable;
PropertyInfo ButtonProperty;
public Xamarin.Forms.Button Button
{
get
{
return (Xamarin.Forms.Button)ButtonProperty.GetMethod.Invoke(_backgroundDrawable, null);
}
set
{
ButtonProperty.SetMethod.Invoke(_backgroundDrawable, new object[] { value });
}
}
public ButtonDrawable()
{
_backgroundDrawable = typeof(Xamarin.Forms.Platform.Android.ButtonRenderer).Assembly.CreateInstance("Xamarin.Forms.Platform.Android.ButtonDrawable");
this.ResetMethod = _backgroundDrawable.GetType().GetMethod("Reset", BindingFlags.Instance | BindingFlags.Public);
this.DisposeMethod = _backgroundDrawable.GetType().GetMethod("Dispose", BindingFlags.Instance | BindingFlags.Public);
this.ButtonProperty = _backgroundDrawable.GetType().GetProperty("Button", BindingFlags.Instance | BindingFlags.Public);
}
MethodInfo ResetMethod;
public void Reset()
{
ResetMethod.Invoke(_backgroundDrawable, null);
}
MethodInfo DisposeMethod;
public void Dispose()
{
DisposeMethod.Invoke(_backgroundDrawable, null);
}
public Android.Graphics.Drawables.Drawable GetDrawable()
{
return _backgroundDrawable as Android.Graphics.Drawables.Drawable;
}
}
}
Without AppCompat
if you want to remove AppCompat you must do two things
Your MainActivity must inherit now from global::Xamarin.Forms.Platform.Android.FormsApplicationActivity
and your style usually in resources/values/styles.xml must inherit from a non-AppCompat style like android:Theme.Material
<resources>
<!-- inherit from the material theme -->
<style name="AppTheme" parent="android:Theme.Material">
<!-- Main theme colors -->
<!-- your app branding color for the app bar -->
<item name="android:colorPrimary">#color/primary</item>
<!-- darker variant for the status bar and contextual app bars -->
<item name="android:colorPrimaryDark">#color/primary_dark</item>
<!-- theme UI controls like checkboxes and text fields -->
<item name="android:colorAccent">#color/accent</item>
</style>
</resources>
Create a style in Content Page resource and and add this style in button.
CornerRadius is must be half of HeightRequest and WidthRequest.
This is for Xamarin.Forms >= 3.4. Now BorderRadius convert into CornerRadius.
<ContentPage.Resources>
<ResourceDictionary>
<Style x:Key="myRoundbutton" TargetType="Button">
<Setter Property="BackgroundColor" Value="Green"/>
<Setter Property="TextColor" Value="White" />
<Setter Property="BorderColor" Value="Blue"/>
<Setter Property="CornerRadius" Value="35"/>
<Setter Property="HeightRequest" Value="70" />
<Setter Property="WidthRequest" Value="70"/>
<Setter Property="BorderWidth" Value="2"/>
<Setter Property="FontAttributes" Value="Bold" />
</Style>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout HorizontalOptions="Fill"
VerticalOptions="Fill">
<Button Image="myBtn3.png"
Command="{Binding LoginCommand}"
Style="{DynamicResource myRoundbutton}" />
</StackLayout>
</ContentPage.Content>

Resources