Design Changes in Xamarin.Forms causes events to fail - xamarin

If I create a new cross platform app and add a button to the default layout and add a click event then all behaves as expected. If I change the layout and place any other elements into the app then the events fail to fire. I am testing against a connected device but have also tried this on an emulator.
This works:
<StackLayout>
<!-- Place new controls here -->
<Button x:Name="Testbtn" Text="Click Me" />
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
public MainPage()
{
InitializeComponent();
Testbtn.Clicked += OnClicked;
}
async void OnClicked(object sender, EventArgs e)
{
var btn = sender as Button;
await DisplayAlert("Test", String.Format("Clicked !! {0}", btn.Text), "OK");
}
When the layout is changed the app re-builds but the events do not fire...
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition Height="3.333" />
<RowDefinition Height="3.333" />
<RowDefinition Height="3.333" />
</Grid.RowDefinitions>
<StackLayout Grid.Row="2" >
<Button x:Name="btnTest" Text="Click Me" />
<Button x:Name="btnTest1" Text="And Another" />
</StackLayout>
</Grid>
public MainPage()
{
InitializeComponent();
Testbtn.Clicked += OnClicked;
Testbtn1.Clicked += OnClicked;
}
async void OnClicked(object sender, EventArgs e)
{
var btn = sender as Button;
await DisplayAlert("Test", String.Format("Clicked !! {0}", btn.Text), "OK");
}

Your buttons are named differently in XAML than what you refer to in the code behind. What you have is:
<Button x:Name="btnTest" Text="Click Me" />
<Button x:Name="btnTest1" Text="And Another" />
so the code behind should be:
btnTest.Clicked += OnClicked;
btnTest1.Clicked += OnClicked;
instead of:
Testbtn.Clicked += OnClicked;
Testbtn1.Clicked += OnClicked;

Related

How to return values from controls in popup and add them to the main page?

The main page has a button for adding new items. When the user presses it, a popup window appears.
I used this code for popup.xaml:
<xct:Popup xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MReport.popup01"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
Size="300,400">
<ScrollView>
<StackLayout Orientation="Vertical" Spacing="10">
<Label Text="From Time:" Padding="5,5,0,0" TextColor="Black"
HorizontalTextAlignment="Start" />
<TimePicker HorizontalOptions="Center" Time="00:00" />
<Label Text="To Time" Padding="5,5,0,0" TextColor="Black"
HorizontalTextAlignment="Start" />
<TimePicker HorizontalOptions="Center"/>
<Label Text="Your Activities:" Padding="5,5,0,0" TextColor="Black" />
<Editor x:Name="editor_value" VerticalOptions="CenterAndExpand" HeightRequest="200" />
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="1" Text="Add" Clicked="Button_Clicked_1" />
<Button Grid.Column="0" Text="Cancel" Clicked="Button_Clicked" />
</Grid>
</StackLayout>
</ScrollView>
</xct:Popup>
For popup.xaml.cs:
using Xamarin.CommunityToolkit.UI.Views;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace MReport
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class popup01 : Popup
{
public popup01()
{
InitializeComponent();
}
private void Button_Clicked(object sender, EventArgs e)
{
Dismiss("Cancelled");
}
private void Button_Clicked_1(object sender, EventArgs e)
{
}
}
}
For TabbedPage:
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MReport.TabbedMainPage">
<!--Pages can be added as references or inline-->
<ContentPage Title="New Report" IconImageSource="NewReport.png" BackgroundImageSource="blue_windows.jpg">
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ScrollView>
<StackLayout>
<Label x:Name="lbl01" />
</StackLayout>
</ScrollView>
<Button Grid.Row="1" Text="Add New Item" Clicked="Button_Clicked"/>
</Grid>
<Button Grid.Row="1" Text="Send Report" />
</StackLayout>
</ContentPage>
<ContentPage Title="Report History" IconImageSource="History.png" BackgroundImageSource="blue_windows.jpg" />
<ContentPage Title="Messages" IconImageSource="Message.png" BackgroundImageSource="blue_windows.jpg"/>
</TabbedPage>
For TabbedPage.xaml.cs:
using Xamarin.Forms.PlatformConfiguration;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Xamarin.Forms.Xaml;
using Xamarin.CommunityToolkit.Extensions;
namespace MReport
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TabbedMainPage : Xamarin.Forms.TabbedPage
{
public TabbedMainPage()
{
InitializeComponent();
On<Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);
On<Android>().SetIsSmoothScrollEnabled(false);
}
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.ShowPopup(new popup01());
}
}
}
I use CommunityToolKit for the popup.
The popup has two buttons. The ADD button will add the information entered in the popup to the main page.
I want the output to be like the image I've provided.
These frame boxes and their texts are added each time the user presses the add button in the popup. Those frame boxes are expanded based on the text volume inside them. What code should be written for the ADD button?
Please help me.
ShowPopupAsync can return a value to the caller
var result = await Navigation.ShowPopupAsync(popup);
whatever parameter is passed to Dismiss() will be returned to the caller

Gesture Recognizer go to detail

i have a page with Cards and once i tap on one i need to get detailed data. I have Gesture recognizer so i am able to navigate to he second page but with no details.
I have tried to add TapGesture in xaml but it didnt work.
This is my xaml
<grial:Repeater
Padding="0"
ItemsSource="{ Binding ListOfBestSellers }"
Orientation="Horizontal"
HeightRequest="200"
Spacing="0"
VerticalOptions="End"
ScrollBarVisibility="Never">
<grial:Repeater.ItemTemplate>
<DataTemplate >
<local:AvatArticleBrowserCardItemTemplate
Padding="10,0,5,5"
WidthRequest="150" >
</local:AvatArticleBrowserCardItemTemplate>
</DataTemplate>
</grial:Repeater.ItemTemplate>
</grial:Repeater>
and Template
<ContentView.Content>
<grial:CardView
VerticalOptions="Fill"
CornerRadius="5" x:Name="articleCard">
<grial:CardView.RowDefinitions>
<RowDefinition
Height="*" />
<RowDefinition
Height="Auto" />
</grial:CardView.RowDefinitions>
<!-- ARTICLE IMAGE -->
<ffimageloading:CachedImage
Grid.Row="0"
Margin="-14,0,-14,10"
Source="{ Binding BackgroundImage }"
Aspect="AspectFill" />
<Grid
Grid.Row="1"
VerticalOptions="End"
RowSpacing="10"
Padding="14,10">
<!-- TITLE -->
<Label
Grid.Row="0"
Text="{ Binding Title }"
FontSize="15"
Style="{ StaticResource LabelBoldStyle }"
TextColor="{ DynamicResource AccentColor }" />
<!-- CATEGORY -->
<Label
Grid.Row="1"
Text="{ Binding Section }"
FontSize="12"
VerticalOptions="Start" />
<!-- DATE -->
<Label
Grid.Row="1"
Text="{ Binding When }"
FontSize="12"
VerticalOptions="Start"
HorizontalOptions="End" />
</Grid>
</grial:CardView>
</ContentView.Content>
This is what i have
async void GoToCardDetail(object sender, EventArgs e)
{
if (LangUpLoggedUser.LoggedIn)
{
await Navigation.PushAsync(new MyArticle());
}
else
{
await Navigation.PushAsync(new Login());
}
}
private void CardDetail()
{
articleCard.GestureRecognizers.Clear();
TapGestureRecognizer gestureRecognizerArticleDetail = new TapGestureRecognizer();
gestureRecognizerArticleDetail.Tapped += GoToCardDetail;
articleCard.GestureRecognizers.Add(gestureRecognizerArticleDetail);
}
But its not giving me detailed data, on my list view from other page i have this
private async void ListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
#if !NAVIGATION
var selectedItem = ((ListView) sender).SelectedItem;
var articlePage = new MyArticle(selectedItem as ArticleDetailData);
await Navigation.PushAsync(articlePage);
#endif
}
my MyArticle const
public MyArticles()
{
InitializeComponent();
BindingContext = new MyArticlesListViewModel(null);
}
/// <summary>
///
/// </summary>
/// <param name="articles"></param>
/// <param name="categoryName"></param>
public MyArticles(List<Article> articles, string categoryName)
{
_categoryName = categoryName;
InitializeComponent();
BindingContext = new MyArticlesListViewModel(articles);
}
And that works perfectly can zou please help me how to achieve the same result?
you need to pass the selected item to MyArticle's constructor
var card = (CardView) sender;
var item = (ArticleDetailData)card.BindingContext;
await Navigation.PushAsync(new MyArticle(item));

Xamarin Forms iOS Navigation PushAsync shows Master Page Title on NavigationBar

In my xamarin.forms project, Page1 is a detail page with master page title on navigatonbar. When i navigate to page3 from page1 viewmodel using PushAsync, page3 has got both master page title and navigationbar backbutton.When i navigate from page1 viewmodel to page2 from inside master page,page2 has only navbackbutton,no master title.When navigating from page2 viewmodel to page3, page3 also do not have master title,only navbackbutton.I do not have this issue on Android.How to hide Master page Title when navigate from page1 viewmodel to page3 on iOS?
page1 cs: vm method called for moving to page3
private async void Cart_Tapped(object sender, EventArgs e)
{
await img_cart.FadeTo(0.3, 500);
await img_cart.FadeTo(1, 500);
var vm = BindingContext as Main_page_vm;
vm?.Save_cart();
}
Navigating from page1 viewmodel to page3: Detail page to content page having issue
internal async void Save_cart()
{
if(Number.Equals(0))
{
App.Current.Properties["cartitems"] = purchaselist;
DependencyService.Get<IToast>().LongAlert("Empty cart !");
}
else
{
App.Current.Properties["cartitems"] = purchaselist;
List<tb_login> Login_list = App.Database.Get_user_id();
if (!Login_list.Count.Equals(0))
{
foreach (tb_login tb_Login in Login_list)
{
App.Current.Properties["user_id"] = tb_Login.user_id;
App.Current.Properties["username"] = tb_Login.user_name;
}
await Navigation.PushAsync(new Address_page2()); //to page3,now showing master
}
else
{
await Navigation.PushAsync(new LoginPage());
}
}
}
Page1 to page2: detail page to content page,No issues
private async void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as HomePageMenuItem;
if (item == null)
return;
if (item.Id == 0)
{
// Detail = new NavigationPage(new HomelyPage());
await Navigation.PushAsync(new HomelyPage());//to page2 has no master issues
}
IsPresented = false;
MasterPage.ListView.SelectedItem = null;
}
Page2 viewmodel to page3:content page to content page,No issues
public async void Save_cart()
{
if (Number.Equals(0))
{
App.Current.Properties["cartitems"] = purchaselist;
DependencyService.Get<IToast>().LongAlert("Empty cart !");
}
else
{
App.Current.Properties["cartitems"] = purchaselist;
List<tb_login> Login_list = App.Database.Get_user_id();
if (!Login_list.Count.Equals(0))
{
foreach (tb_login tb_Login in Login_list)
{
App.Current.Properties["user_id"] = tb_Login.user_id;
App.Current.Properties["username"] = tb_Login.user_name;
}
await Navigation.PushAsync(new Address_page2()); //to page3,also not showing master
}
else
{
await Navigation.PushAsync(new LoginPage());
}
}
}
page1 xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="OnRestaur.Views.Main_Page"
BackgroundColor="#f2f2f2"
NavigationPage.HasBackButton="False">
<NavigationPage.TitleView>
<StackLayout HorizontalOptions="EndAndExpand">
<Grid HorizontalOptions="EndAndExpand">
<Label Text="{Binding Number, Mode=TwoWay}" FontAttributes="Bold" HorizontalOptions="EndAndExpand" FontSize="Small" VerticalTextAlignment="Center" HorizontalTextAlignment="Center" Margin="0,0,32,10" Style="{StaticResource Label_font}" TextColor="White">
</Label>
<Image Source="shoppingcart_white.png" x:Name="img_cart" HorizontalOptions="EndAndExpand" WidthRequest="60" HeightRequest="50" Margin="0,0,10,0">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Cart_Tapped" />
</Image.GestureRecognizers>
</Image>
</Grid>
</StackLayout>
</NavigationPage.TitleView>
Page3 xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="OnRestaur.Views.Address_page2"
NavigationPage.HasBackButton="False"
Title=" ">
<NavigationPage.TitleView>
<StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal" Margin="0" Spacing="0" Padding="0">
<Image Source="back_arrow.png" x:Name="img_cart" HorizontalOptions="StartAndExpand" WidthRequest="30" HeightRequest="30" Margin="0,0,0,0">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Back_arrow_Tapped" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</NavigationPage.TitleView>
page2 xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
Title="Home"
x:Class="OnRestaur.Views.HomelyPage"
xmlns:local="OnRestaur.Views;assembly=ContentView"
xmlns:custom="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin"
NavigationPage.HasBackButton="False">
<NavigationPage.TitleView>
<StackLayout HorizontalOptions="FillAndExpand" Orientation="Horizontal">
<Image Source="back_arrow.png" HorizontalOptions="StartAndExpand" WidthRequest="30" HeightRequest="30" Margin="0,0,0,0">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Back_arrow_Tapped" />
</Image.GestureRecognizers>
</Image>
<Grid HorizontalOptions="EndAndExpand">
<Image Source="loc.png" x:Name="img_cart" HorizontalOptions="EndAndExpand" WidthRequest="20" HeightRequest="20" Margin="0,0,30,0">
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="Loc_Tapped" />
</Image.GestureRecognizers>
</Image>
</Grid>
</StackLayout>
</NavigationPage.TitleView>
Change the Navigation to something like below and it should solve your issue:
Application.Current.MainPage.Navigation.PushAsync(new Address_page2());

editor length validation xamarin forms

I would like to do some validation to this editor , for example "editor can not be empty write something". I could validate as input < 0 , however, I will need this validation in order to go to the next page . Any ideas ? Thanks.
this is my xaml.
<StackLayout Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="3">
<Label Text="Description" FontSize="Medium" Style="{StaticResource LabelStyle}" />
<Editor x:Name="Description" FontSize="Medium" HeightRequest="120" TextChanged ="Handle_TextChanged" />
<Label x:Name ="Errorlabel"/>
</StackLayout>
cs:
async void Send_Activated(object sender, System.EventArgs e)
{
var editor = EDescription.Text;
if (string.IsNullOrWhiteSpace (editor))
{
Errorlabel.Text = "Plase add a description ";
ToolbarItems.Clear();
}
if (editor.Length >1)
{
await App.Navigator.PushAsync(new 2View());
}
}
toolbar :
<ContentPage.ToolbarItems>
<ToolbarItem x:Name = "anySend" Text="Send" Order="Primary" Activated="Send_Activated" />
</ContentPage.ToolbarItems>
a simple way to validate for non-null entries:
if (string.IsNullOrEmpty(Description.Text)) {
DisplayAlert("Error","Please enter a description", "OK");
} else {
Navigation.PushAsync(nextPage);
}
Xamarin also has an extensive writeup on doing Validation in MVVM

How to display a ListView and Other Controls in a ScrollView?

I want to display a ListView and other controls inside a ScrollView. All is bound to a ViewModel. My attempts failed because it's not recommend to put a ListView inside a ScrollView. As I use a complex ViewCell DataTemplate, I did not consider to add my items in the code behind file as Buttons instead of a ListView.
Hope someone can show me a Xaml or CS pattern to achieve my goal.
Please only suggest a solution which works on iOS and Android!
Thanks
Eric
This is XAML code
<ScrollView Padding="2">
<StackLayout HorizontalOptions="FillAndExpand">
<Grid HorizontalOptions="FillAndExpand">
<StackLayout>
<ScrollView Orientation="Horizontal">
<ListView BackgroundColor="Transparent" ItemsSource="{Binding UsersList}" SeparatorVisibility="None" x:Name="YourListView" RowHeight="50">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout BackgroundColor="Transparent" Padding="5">
<Button Text="{Binding UserName}" WidthRequest="115" HorizontalOptions="FillAndExpand" TextColor="White" BackgroundColor="#4b76c4" FontAttributes="Bold" FontSize="20" FontFamily="Avenir Book"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollView>
</StackLayout>
</Grid>
</StackLayout>
</ScrollView>
and .cs file you need set BindingContext
BindingContext = new YourViewModel();
Solution:
As Rodrigo E suggested I download the latest Xamarin Evolve App 2016. After digging through the code I adjusted/simplified the FeedPage.xaml in the solution to that:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamarinEvolve.Clients.UI;assembly=XamarinEvolve.Clients.UI"
xmlns:pull="clr-namespace:Refractored.XamForms.PullToRefresh;assembly=Refractored.XamForms.PullToRefresh"
x:Class="XamarinEvolve.Clients.UI.FeedPage"
x:Name="FeedPage"
Title="Evolve Feed"
Icon="tab_feed.png"
BackgroundColor="{DynamicResource WindowBackgroundTable}">
<pull:PullToRefreshLayout
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsBusy}">
<local:AlwaysScrollView
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout>
<StackLayout Spacing="0">
<local:NonScrollableListView
x:Name="ListViewSessions"
ItemsSource="{Binding Sessions}">
<local:NonScrollableListView.RowHeight>
<OnPlatform x:TypeArguments="x:Int32" Android="50" iOS="50" WinPhone="50"/>
</local:NonScrollableListView.RowHeight>
<local:NonScrollableListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Button Text="{Binding Title}" BackgroundColor="Black" TextColor="Green" />
</ViewCell>
</DataTemplate>
</local:NonScrollableListView.ItemTemplate>
</local:NonScrollableListView>
</StackLayout>
<StackLayout Padding="0" Spacing="0" BackgroundColor="Green">
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
<Button Text="OTHER" BackgroundColor="Blue" TextColor="White" />
</StackLayout>
</StackLayout>
</local:AlwaysScrollView>
</pull:PullToRefreshLayout>
There are a few things to do:
In the FeedViewModel.cs I added that code for a quick test:
async Task ExecuteLoadSessionsCommandAsync()
{
if (LoadingSessions)
return;
LoadingSessions = true;
try
{
NoSessions = false;
Sessions.Clear();
OnPropertyChanged("Sessions");
#if DEBUG
await Task.Delay(1000);
#endif
var sessions = await StoreManager.SessionStore.GetNextSessions();
var testSessions = new List<Session>();
testSessions.Add(new Session
{
Title = "TEST"
});
testSessions.Add(new Session
{
Title = "TEST"
});
testSessions.Add(new Session
{
Title = "TEST"
});
sessions = testSessions;
if(sessions != null)
Sessions.AddRange(sessions);
NoSessions = Sessions.Count == 0;
}
catch(Exception ex)
{
ex.Data["method"] = "ExecuteLoadSessionsCommandAsync";
Logger.Report(ex);
NoSessions = true;
}
finally
{
LoadingSessions = false;
}
}
You have to reference the package Refractored.XamForms.PullToRefresh to get the Pull-to-Refresh behavor.
This is in that namespace referenced: xmlns:pull="clr-namespace:Refractored.XamForms.PullToRefresh;assembly=Refractored.XamForms.PullToRefresh"
You have to Copy the AlwaysScrollView , NonScrollableListView to your PCL library.
refercene it with: xmlns:local="clr-namespace:"
In your iOS Project add that custom ListView Renderer:
public class NonScrollableListViewRenderer : ListViewRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (Control != null)
Control.ScrollEnabled = false;
}
}
public class AlwaysScrollViewRenderer : ScrollViewRenderer
{
public static void Initialize()
{
var test = DateTime.UtcNow;
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
this.AlwaysBounceVertical = true;
}
}
See file: Renderer
Put that CollectionChanged Handler in your Code-behind file:
ViewModel.Sessions.CollectionChanged += (sender, e) =>
{
var adjust = Device.OS != TargetPlatform.Android ? 1 : -ViewModel.Sessions.Count + 1;
ListViewSessions.HeightRequest = (ViewModel.Sessions.Count * ListViewSessions.RowHeight) - adjust;
};
See File FeedPage.cs.xaml: FeedPage.cs.xaml

Resources