How to create click event on label in xamarin forms dynamically - c#

I am working on cross platform xamarin application and I want to create hyperlink label for "Forgot password?" on login page.
I have used following code to create label but I don't know how to create onclick event on it.
MainPage = new ContentPage
{
BackgroundImage = "background.png",
Content = new StackLayout
{
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Spacing = 50,
Children = {
new Label {
HorizontalTextAlignment = TextAlignment.Center,
Text = "Welcome, Please Sign in!",
FontSize=50,
TextColor=Color.Gray,
},
new Entry
{
Placeholder="Username",
VerticalOptions = LayoutOptions.Center,
Keyboard = Keyboard.Text,
HorizontalOptions = LayoutOptions.Center,
WidthRequest = 350,
HeightRequest = 50,
FontSize=20,
TextColor=Color.Gray,
PlaceholderColor=Color.Gray,
},
new Entry
{
Placeholder="Password",
VerticalOptions = LayoutOptions.Center,
Keyboard = Keyboard.Text,
HorizontalOptions = LayoutOptions.Center,
WidthRequest = 350,
HeightRequest = 50,
FontSize=25,
TextColor=Color.Gray,
IsPassword=true,
PlaceholderColor =Color.Gray,
},
new Button
{
Text="Login",
FontSize=Device.GetNamedSize(NamedSize.Large,typeof(Button)),
HorizontalOptions=LayoutOptions.Center,
VerticalOptions=LayoutOptions.Fill,
WidthRequest=350,
TextColor=Color.Silver,
BackgroundColor=Color.Red,
BorderColor=Color.Red,
},
new Label //for this label I want to create click event to open new page
{
Text="Forgot Password?",
FontSize=20,
TextColor=Color.Blue,
HorizontalOptions=LayoutOptions.Center,
},
}
}
};

For people who prefer to use XAML and who like to bind Command directly to the ViewModel, you can use this:
<Label HorizontalOptions="Center"
TextColor="Blue"
FontSize="20"
Text="Forgot Password?">
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ForgotPasswordCommand}" />
</Label.GestureRecognizers>
</Label>
And then in your ViewModel, you'll just assign the command to your function:
public ICommand ForgotPasswordCommand => new Command(OnForgotPassword);
And then define the function with all the work get done:
private async void OnForgotPassword()
{ ... }
PS: You will need to declare that you are using System.Windows.Input;

Try this :
var forgetPasswordLabel = new Label // Your Forget Password Label
{
Text = "Forgot Password?",
FontSize = 20,
TextColor = Color.Blue,
HorizontalOptions = LayoutOptions.Center,
};
// Your label tap event
var forgetPassword_tap = new TapGestureRecognizer();
forgetPassword_tap.Tapped += (s,e) =>
{
//
// Do your work here.
//
};
forgetPasswordLabel.GestureRecognizers.Add(forgetPassword_tap);
Sample :
var forgetPasswordLabel = new Label // Your Forget Password Label
{
Text = "Forgot Password?",
FontSize = 20,
TextColor = Color.Blue,
HorizontalOptions = LayoutOptions.Center,
};
MainPage = new ContentPage
{
BackgroundImage = "background.png",
Content = new StackLayout
{
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
Spacing = 50,
Children = {
new Label {
//HorizontalTextAlignment = TextAlignment.Center,
Text = "Welcome, Please Sign in!",
FontSize=50,
TextColor=Color.Gray,
},
new Entry
{
Placeholder="Username",
VerticalOptions = LayoutOptions.Center,
Keyboard = Keyboard.Text,
HorizontalOptions = LayoutOptions.Center,
WidthRequest = 350,
HeightRequest = 50,
FontSize=20,
TextColor=Color.Gray,
PlaceholderColor=Color.Gray,
},
new Entry
{
Placeholder="Password",
VerticalOptions = LayoutOptions.Center,
Keyboard = Keyboard.Text,
HorizontalOptions = LayoutOptions.Center,
WidthRequest = 350,
HeightRequest = 50,
FontSize=25,
TextColor=Color.Gray,
IsPassword=true,
PlaceholderColor =Color.Gray,
},
new Button
{
Text="Login",
FontSize=Device.GetNamedSize(NamedSize.Large,typeof(Button)),
HorizontalOptions=LayoutOptions.Center,
VerticalOptions=LayoutOptions.Fill,
WidthRequest=350,
TextColor=Color.Silver,
BackgroundColor=Color.Red,
BorderColor=Color.Red,
},
forgetPasswordLabel
}
}
};
var forgetPassword_tap = new TapGestureRecognizer();
forgetPassword_tap.Tapped += (s,e) =>
{
//
// Do your work here.
//
};
forgetPasswordLabel.GestureRecognizers.Add(forgetPassword_tap);

If the're several places with clickable Label, it makes sense to create a control inheriting from Xamarin.Forms Label and DO NOT PUT TapGestureRecognizer everywhere the label is required.
public class ExtendedLabel : Label
{
private event EventHandler click;
public string Name
{
get; set;
}
public void DoClick()
{
click?.Invoke(this, null);
}
public event EventHandler Clicked
{
add
{
lock (this)
{
click += value;
var g = new TapGestureRecognizer();
g.Tapped += (s, e) => click?.Invoke(s, e);
GestureRecognizers.Add(g);
}
}
remove
{
lock (this)
{
click -= value;
GestureRecognizers.Clear();
}
}
}
}
In your XAML file you import the namespace where the control is defined, e.g.
<ContentPage xmlns:ctrl="clr-namespace:UICore.Controls" ...
And use it as ordinary control:
<ctrl:ExtendedLabel x:Name="quitButton" Clicked="OnQuit">

MyClickyLabel.GestureRecognizers.Add(
new TapGestureRecognizer() {
Command = new Command(() => {
/* Handle the click here */
} )
}
);

Related

How to access components created in Xamarin.Forms C# code behind?

So, I'm doing an app in Xamarin.Forms that creates some components and layouts when a button is clicked.
My problem is that I need to access these components afterwards so I can change the text in some labels, get values from editors and remove them later if necessary...
This is the piece of code that creates the components:
private void newItem()
{
StackLayout add = new StackLayout { };
add.StyleId = "add_" + posicio;
elements.Children.Add(add);
StackLayout grupInical = new StackLayout
{
Orientation = StackOrientation.Horizontal
};
add.Children.Add(grupInical);
Label number = new Label
{
VerticalOptions = LayoutOptions.End,
HorizontalOptions = LayoutOptions.StartAndExpand,
Text = "Element" + posicio.ToString(),
FontAttributes = FontAttributes.Bold,
Margin = new Thickness(5, 0, 0, 0)
};
Button tancar = new Button
{
Padding = new Thickness(5),
Text = "✕",
HorizontalOptions = LayoutOptions.End,
BackgroundColor = Color.Transparent,
WidthRequest = 30,
HeightRequest = 30
};
number.StyleId = "number_" + posicio;
tancar.StyleId = "tancar_" + posicio;
tancar.Clicked += Eliminar_clicked;
grupInical.Children.Add(number_);
grupInical.Children.Add(tancar);
StackLayout values = new StackLayout
{
Orientation = StackOrientation.Horizontal
};
values.StyleId = "values" + posicio;
add.Children.Add(values);
Button elegir = new Button
{
Text = "Element"
};
Editor percentage = new Editor { MaxLength = 2, WidthRequest = 30 };
Label desc = new Label
{
VerticalOptions = LayoutOptions.Center,
FontSize = 20,
FontAttributes = FontAttributes.Bold,
Text = "%"
};
Picker picker = new Picker
{
IsVisible = false
};
elegir.Clicked += Elegir_Clicked;
elegir.StyleId = "elegir_"+posicio;
percentatge.StyleId = "percentatge_" + posicio;
desc.StyleId = "desc_" + posicio;
picker.StyleId = "picker_" + posicio;
values.Children.Add(elegir);
values.Children.Add(percentatge);
values.Children.Add(desc);
values.Children.Add(picker);
posicio += 1;
scroll.ScrollToAsync(0, elements.Height, true);
}
As you can see, I'm trying to access the components by assigning them a styleid value but I can't access the component.
Have you got any suggestions on how to identify the items so I can reference them later on?
Declare these components at the class level and then you can access them in the other place in your project.
public partial class MainPage : ContentPage
{
Label numberLabel;
StackLayout myAddStackLayout;
public MainPage()
{
InitializeComponent();
newItem()
numberLabel.Text = "updateValue";
myAddStackLayout.Children.Add(...);
}
public void test() {
numberLabel.Text = "updateValue";
myAddStackLayout.Children.Add(...);
}
private void newItem()
{
StackLayout add = new StackLayout { };
Label number = new Label ();
}
}

Microsoft Android Emulator Shows Blank Form When Debugging

I am trying to run a Xamarin form called 'FormsApp' on my andriod emulator in visual studio. The Emulator boots up fine and renders. However, after clicking "start debugging" the form deploys to the emulator but only shows a blank white from.
https://i.imgur.com/AbkqDyJ.png
https://i.imgur.com/VttMKfh.png
I have tried playing around with my OpenGL ES Renderer settings and OpenGL ES API level settings as well. Switching to swiftshader/ANGLE D3D9/ and Compatibility (OpenGL ES 1.1/2.0) did not work. It's Still a blank white Screen when debugging.
namespace FormsApp
{
class ContentPageExample : ContentPage
{
public ContentPageExample()
{
Label labelLarge = new Label
{
Text = "Label",
FontSize = 40,
HorizontalOptions = LayoutOptions.Center
};
Label labelSmall = new Label
{
Text = "This control is great for\n" +
"displaying one or more\n" +
"lines of text.",
FontSize = 20,
HorizontalOptions = LayoutOptions.CenterAndExpand
};
Button button = new Button
{
Text = "Make It So",
FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Button)),
HorizontalOptions = LayoutOptions.Center,
VerticalOptions = LayoutOptions.Fill
};
button.Clicked += (sender, args) =>
{
button.Text = "It is so!";
};
Entry entry = new Entry
{
Placeholder = "Username",
VerticalOptions = LayoutOptions.Center,
Keyboard = Keyboard.Text
};
BoxView boxView = new BoxView
{
Color = Color.Silver,
WidthRequest = 150,
HeightRequest = 150,
HorizontalOptions = LayoutOptions.StartAndExpand,
VerticalOptions = LayoutOptions.Fill
};
Image image = new Image
{
Source = "monkey.png",
Aspect = Aspect.AspectFit,
HorizontalOptions = LayoutOptions.End,
VerticalOptions = LayoutOptions.Fill
};
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.Tapped += async (sender, e) =>
{
image.Opacity = .5;
await Task.Delay(200);
image.Opacity = 1;
};
image.GestureRecognizers.Add(tapGestureRecognizer);
StackLayout stackLayout = new StackLayout
{
Children =
{
labelLarge,
labelSmall,
button,
entry,
boxView,
image
},
HeightRequest = 1500
};
ScrollView scrollView = new ScrollView
{
//BackgroundColor = Color.White,
VerticalOptions = LayoutOptions.FillAndExpand,
Content = stackLayout
};
//this.BackgroundColor = Color.Black; //White
// Accomodate iPhone status bar.
this.Padding = new Thickness(10, Device.OnPlatform(20, 0, 0), 10, 5);
this.Content = scrollView;
}
}
}
No error messages..
Did you set the ContentPageExample as MainPage? I just test the ContentPageExample and it works well.
For example in class App:
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new ContentPageExample();
}
}

Remove extra space from FlexLayout

Question
I have a FlexLayout with following properties. Whenever any element is added to it(except the first one), extra space gets added automatically. How do I get rid of that extra space?
var flexLayout = new FlexLayout
{
Wrap = FlexWrap.Wrap,
JustifyContent = FlexJustify.Start,
AlignItems = FlexAlignItems.Center,
AlignContent = FlexAlignContent.Start,
BackgroundColor = Color.LightYellow,
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.Start
};
Here is the result -
Detailed Question
My scenario is to add multiple Flexlayouts inside a StackLayout which is child of a ScrollView.
Everything is working fine except Flexlayouts takes lot of unused white space, I want them to fit to children.
So far I have tried
1. Lot of permutation combinations of FlexLayout properties.
2. Putting Flexlayout inside StackLayout/ Grid with VerticalOptionsset to Start
XAML
<Grid>
<ScrollView HorizontalScrollBarVisibility="Never">
<StackLayout x:Name="RootPanel" BackgroundColor="Cyan" Padding="5"/>
</ScrollView>
</Grid>
C# Code behind
private void Draw()
{
string[] data = new string[] { "Button1", "Button1", "Button1", "Button1", "Button1", "Button1", "Button1", "Button1", "Button1" };
for (int i = 0; i < 5; i++)
{
var tempLayout = new StackLayout
{
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.Start
};
var fButton = new Button { Text = "B", HorizontalOptions = LayoutOptions.Start, VerticalOptions = LayoutOptions.Start, WidthRequest = 50, HeightRequest = 50 };
tempLayout.Children.Add(fButton);
var equals = new Label { Text = "=>", VerticalTextAlignment = TextAlignment.Center, HorizontalTextAlignment = TextAlignment.Center, VerticalOptions = LayoutOptions.Start, WidthRequest = 50, HeightRequest = 50, BackgroundColor = Color.LemonChiffon };
tempLayout.Children.Add(equals);
var flexLayout = new FlexLayout
{
Wrap = FlexWrap.Wrap,
JustifyContent = FlexJustify.Start,
AlignItems = FlexAlignItems.Center,
AlignContent = FlexAlignContent.Start,
BackgroundColor = Color.LightYellow,
HorizontalOptions = LayoutOptions.FillAndExpand
};
foreach (var term in data)
{
var button = new Button { Text = term, HorizontalOptions = LayoutOptions.Start, VerticalOptions = LayoutOptions.Start, HeightRequest = 36 };
flexLayout.Children.Add(button);
var label = new Label { Text = "and", VerticalTextAlignment = TextAlignment.Center, HorizontalTextAlignment = TextAlignment.Center, VerticalOptions = LayoutOptions.Start, HeightRequest = 50, BackgroundColor = Color.LemonChiffon };
flexLayout.Children.Add(label);
}
//var grid = new Grid { HorizontalOptions = LayoutOptions.StartAndExpand, VerticalOptions = LayoutOptions.Start, BackgroundColor = Color.Red };
//grid.Children.Add(flexLayout);
tempLayout.Children.Add(flexLayout);
//Grid.SetColumn(tempLayout, 1);
//grid.Children.Add(tempLayout);
RootPanel.Children.Add(tempLayout);
}
}
Above code gives following result, screenshot is from a UWP app but the result is same for Android also -
I am expecting something like this, there is no empty space after array of buttons.
Cause: The parent layout of FlexLayout is a StackLayout .And StackLayout will fit the size of its child elements.
Solution:
Use Grid instead of Stacklayout
private void Draw()
{
string[] data = new string[] { "Button1", "Button1", "Button1", "Button1", "Button1", "Button1", "Button1", "Button1", "Button1" };
for (int i = 0; i < 5; i++)
{
var grid = new Grid
{
BackgroundColor = Color.Green
};
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(50) });
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
var fButton = new Button { Text = "B", HorizontalOptions = LayoutOptions.Start, VerticalOptions = LayoutOptions.Start, WidthRequest = 50, HeightRequest = 50 };
grid.Children.Add(fButton, 0, 0);
var equals = new Label { Text = "=>", VerticalTextAlignment = TextAlignment.Center, HorizontalTextAlignment = TextAlignment.Center, VerticalOptions = LayoutOptions.Start, WidthRequest = 50, HeightRequest = 50, BackgroundColor = Color.LemonChiffon };
grid.Children.Add(equals, 1, 0);
var flexLayout = new FlexLayout
{
Wrap = FlexWrap.Wrap,
JustifyContent = FlexJustify.SpaceAround,
AlignItems = FlexAlignItems.Start,
AlignContent = FlexAlignContent.Start,
BackgroundColor = Color.Red,
HorizontalOptions = LayoutOptions.FillAndExpand,
};
foreach (var term in data)
{
var button = new Button { Text = term, HorizontalOptions = LayoutOptions.Start, VerticalOptions = LayoutOptions.Start, HeightRequest = 36 };
flexLayout.Children.Add(button);
var label = new Label { Text = "and", VerticalTextAlignment = TextAlignment.Center, HorizontalTextAlignment = TextAlignment.Center, VerticalOptions = LayoutOptions.Start, HeightRequest = 50, BackgroundColor = Color.LemonChiffon };
flexLayout.Children.Add(label);
}
grid.Children.Add(flexLayout, 2, 0);
RootPanel.Children.Add(grid);
}
}
Don't use GRID inside FlexLyout it will give a huge WHITE SPACE, Use StackLayout instead
Mark the StackLayout Spacing value to 0. There is a default spacing of 10 points. https://learn.microsoft.com/en-us/dotnet/api/xamarin.forms.stacklayout.spacing?view=xamarin-forms

How to add TapGestureRecognizer to StackLayout?

So I have this following code:
foreach (var a in abc)
{
var viewCell = new ViewCell
{
View = new StackLayout()
{
//// I want to add TapGestureRecognizer on this outer stacklayout
Padding = new Thickness(20, 0, 20, 0),
HorizontalOptions = LayoutOptions.FillAndExpand,
Children = {
new StackLayout() {
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.CenterAndExpand,
Children = {
new StackLayout() {
HorizontalOptions = LayoutOptions.StartAndExpand,
Children = {
new Label { Text = a.Name}}
},
new StackLayout() {
HorizontalOptions = LayoutOptions.EndAndExpand,
Orientation = StackOrientation.Horizontal,
Children = {
new Label { Text = a.Count},
new Image { Source = "right1.png" }
}
}
}
}
}
}
};
tableSection.Add(viewCell);
}
What this code basically do is repeat the rows(ViewCell) of my TableView depending on the number of objects in the abc. I want to add a tap event on the outer (first Stacklayout) but I can't seem to find out how to do it with my how my ViewCell is set up. Anyone has any idea?
You should create your StackLayout in a variable first and then add a TapGestureRecognizer to it:
foreach (var a in abc)
{
var stackLayout = new StackLayout()
{
//// I want to add TapGestureRecognizer on this outer stacklayout
Padding = new Thickness(20, 0, 20, 0),
HorizontalOptions = LayoutOptions.FillAndExpand,
Children = {
new StackLayout() {
Orientation = StackOrientation.Horizontal,
VerticalOptions = LayoutOptions.CenterAndExpand,
Children = {
new StackLayout() {
HorizontalOptions = LayoutOptions.StartAndExpand,
Children = {
new Label { Text = a.Name}}
},
new StackLayout() {
HorizontalOptions = LayoutOptions.EndAndExpand,
Orientation = StackOrientation.Horizontal,
Children = {
new Label { Text = a.Count},
new Image { Source = "right1.png" }
}
}
}
}
}
};
var tgr = new TapGestureRecognizer();
tgr.Tapped += (s,e) => OnTgrClicked();
stackLayout.GestureRecognizers.Add(tgr);
var viewCell = new ViewCell
{
View = stackLayout;
};
tableSection.Add(viewCell);
}

xamarin.forms scrollview keyboard appears and button also scroll

Hi i have a weird problem.
I defined few labels and textbox for data entry purpose using xamarin.forms.
I wrapped them into scroll view so that when keyboard appears, they should scroll.
It is working fine. The control which has focus scroll to top and the keyboard appears when it get focus. but i also have couple of buttons at the bottom of my form. Now, the problem is, whenever keyboard appears, my bottom buttons are also scrolled. which looks weird. As button are for submit or cancel, it should be stay there in bottom.
following is my code:
var firstNameLabel = new Label { HorizontalOptions = LayoutOptions.Fill };
firstNameLabel.Text = "First Name";
var firstName = new Entry() { HorizontalOptions = LayoutOptions.FillAndExpand };
firstName.SetBinding (Entry.TextProperty,MyViewModel.FirstNamePropertyName);
var lastNameLabel = new Label { HorizontalOptions = LayoutOptions.Fill};
lastNameLabel.Text = "Last Name";
var lastName = new Entry() { HorizontalOptions = LayoutOptions.FillAndExpand };
lastName.SetBinding (Entry.TextProperty, MyViewModel.LastNamePropertyName);
---- other fields
Button btnSubmit = new Button
{
HorizontalOptions = LayoutOptions.Fill,
BackgroundColor = Color.FromHex("#22498a"),
TextColor = Color.White,
Text = "Submit"
};
var cancelButton = new Button { Text = Cancel", BackgroundColor = Color.FromHex("0d9c00"), TextColor = Color.White };
contactUsButton.Clicked += (object sender, EventArgs e) =>
{
// cancel operation
};
var cotrolStakeLayout = new StackLayout () {
Padding = new Thickness(Device.OnPlatform(5, 5, 5),0 , Device.OnPlatform(5, 5, 5), 0), //new Thickness(5,0,5,0),
VerticalOptions = LayoutOptions.FillAndExpand,
HorizontalOptions = LayoutOptions.Fill,
Orientation = StackOrientation.Vertical,
Children = { firstNameLabel, firstName, lastNameLabel, lastName, -- and other fields}
};
var scrollableContentLayout = new ScrollView (){
Content = cotrolStakeLayout,
Orientation = ScrollOrientation.Vertical,
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill
};
var buttonLayout = new StackLayout (){
Padding = new Thickness(Device.OnPlatform(5, 5, 5),0 , Device.OnPlatform(5, 5, 5), 0), //new Thickness(5,0,5,0),
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
Orientation = StackOrientation.Vertical,
Children= { btnSubmit , cancelButton }
};
var nameLayout = new StackLayout()
{
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.Fill,
Orientation = StackOrientation.Vertical,
Children = {scrollableContentLayout,buttonLayout}
};
return nameLayout;
Any ideas what is wrong with it?
You have to change your layout to reach your target:
- Define a "Main-StackLayout"
- Create a "Button-StackLayout" for your Buttons (that should stay on top)
- Add your Buttons to the "Button-StackLayout"
- Add the "button-StackLayout to the "Main-StackLayout"
- Add the ScrollView to to "Main-StackLayout"
- Set content of the page to the "Main-StackLayout"
This should work: buttons stays on top, where (only) the ScrollView can be scrolled.

Categories