Adjusting UI for different platforms - android

I am working on a Xamarin.Forms (Portable) using Visual Studio 2015.
The application allows me to retrieve information from a Database and display it.
I am able to display all the created records in a ListView on UWP. However, on Android they are not all showing up.
From my Menu Page, you can clearly see the big difference in terms of UI size. I am curious to know why this is happening on the Android platform.
Below are some of the relevant code. If you need to see more, please let me know.
MenuPage.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="XamarinFormsDemo.Views.MenuPage"
BackgroundImage="bg3.jpg">
<StackLayout>
<StackLayout Orientation="Vertical"
Padding="30"
HeightRequest="30"
BackgroundColor="#24e97d">
<Image Source="ebmspersonnellogo1.png"
HeightRequest="40"/>
</StackLayout>
<StackLayout Orientation="Vertical"
VerticalOptions="Center"
Padding="45,60,45,60">
<Image x:Name="sales"
Source="salesicon.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="SalesTapGestureRecognizer_OnTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
<Image x:Name="personnel"
Source="personnelicon.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="PersonnelTapGestureRecognizer_OnTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
<Image x:Name="crm"
Source="crmicon.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="CRMTapGestureRecognizer_OnTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
<Image x:Name="asset"
Source="asseticon.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="AssetTapGestureRecognizer_OnTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
<Image x:Name="receivables"
Source="receivables.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="ReceivablesTapGestureRecognizer_OnTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
<Image x:Name="prapprovals"
Source="prapprovals.png">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="ApprovalsTapGestureRecognizer_OnTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
<StackLayout Orientation="Vertical"
Padding="30,10,30,10"
HeightRequest="20"
BackgroundColor="#24e97d"
VerticalOptions="Center"
Opacity="0.5">
<Label Text="© Copyright 2015 smesoft.com.ph All Rights Reserved "
HorizontalTextAlignment="Center"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</StackLayout>
</ContentPage>
MenuPage.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace XamarinFormsDemo.Views
{
public partial class MenuPage : ContentPage
{
public MenuPage()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
}
private async void NavigateButton_OnClicked(object sender, EventArgs e)
{
await Navigation.PushAsync(new EmployeeRecordsPage());
}
private async void SalesTapGestureRecognizer_OnTapped(Object sender, EventArgs e)
{
await sales.ScaleTo(0.95, 80, Easing.CubicOut);
await sales.ScaleTo(1, 80, Easing.CubicIn);
await Navigation.PushModalAsync(new SalesAndExpensePage());
}
private async void PersonnelTapGestureRecognizer_OnTapped(Object sender, EventArgs e)
{
await personnel.ScaleTo(0.90, 75, Easing.CubicOut);
await personnel.ScaleTo(1, 75, Easing.CubicIn);
await Navigation.PushModalAsync(new PersonnelPage());
}
private async void CRMTapGestureRecognizer_OnTapped(Object sender, EventArgs e)
{
await crm.ScaleTo(0.90, 75, Easing.CubicOut);
await crm.ScaleTo(1, 75, Easing.CubicIn);
await Navigation.PushModalAsync(new CRMPage());
}
private async void AssetTapGestureRecognizer_OnTapped(Object sender, EventArgs e)
{
await asset.ScaleTo(0.90, 75, Easing.CubicOut);
await asset.ScaleTo(1, 75, Easing.CubicIn);
await Navigation.PushModalAsync(new AssetManagementPage());
}
private async void ReceivablesTapGestureRecognizer_OnTapped(Object sender, EventArgs e)
{
await receivables.ScaleTo(0.90, 75, Easing.CubicOut);
await receivables.ScaleTo(1, 75, Easing.CubicIn);
await Navigation.PushModalAsync(new ReceivablesAndPayablesPage());
}
private async void ApprovalsTapGestureRecognizer_OnTapped(Object sender, EventArgs e)
{
await prapprovals.ScaleTo(0.90, 75, Easing.CubicOut);
await prapprovals.ScaleTo(1, 75, Easing.CubicIn);
await Navigation.PushModalAsync(new ApprovalsPage());
}
}
}
Here's a screen shot of UWP and Android. First image is UWP, second image is Android.

First of all. Your view is awfully nested, which can lead to performance problems.
Second of all. You are saying you are using a ListView. However, I don't see it anywhere in your XAML. There you are just using a StackLayout and stacking views below each other.
This means that any item that cannot fit within the screen will not be displayed at all. Consider rewriting your UI and use a ListView instead. Your items are very similar to each other and only title, image and click handler differ from each other. Using a ListView could also eliminate repeating yourself as you do currently with all those tap handlers, and you could limit yourself to only have one.
You could have something like this:
public class MenuItemViewModel
{
public string Name { get; set; }
public string ImageUrl { get; set; }
}
Then in your ViewModel for the page:
public List<MenuItemViewModel> MenuItems { get; } = new List<MenuItemViewModel>();
MenuItems.Add(new MenuItemViewModel {
Name = "Sales and Expense",
ImageUrl = "salesicon.png"
});
MenuItems.Add(new MenuItemViewModel {
Name = "Personnel",
ImageUrl = "personnelicon.png"
});
...
Then in your XAML something like this:
<ListView x:Name="MenuList">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="15,0">
<Label Text="{Binding Name}" />
<Image Source="{Binding ImageUrl}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Then set ItemsSource of the ListView to your MenuItems from your ViewModel.
You can get the selected item by subscribing to ItemSelected on the ListView:
MenuList.ItemSelected += ItemSelected;
private async void ItemSelected(object sender, ItemTappedEventArgs e)
{
var menuItem = e.Item as MenuItemViewModel;
if (menuItem == null) return;
Page nextPage = null;
switch(menuItem.Name)
{
case "Sales and Expense":
nextPage = new SalesAndExpensePage();
break;
case "Personnel":
nextPage = new PersonnelPage();
break;
}
await Navigation.PushModalAsync(nextPage);
}

Related

Load Embedded Resources as Images in MAUI

I created a simple program with MAUI to load 2 images, specified as Embedded Resources.
This is the MainPage:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Surprise.MainPage">
<ScrollView>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="550"/>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<VerticalStackLayout x:Name="ImageContainer"
Grid.Row="0"
HeightRequest="500"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Grid Grid.Row="1"
HorizontalOptions="Center"
HeightRequest="40">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Text="Image1"
Grid.Column="0"
Clicked="OnImage1ButtonClicked" />
<Button Text="Image2"
Grid.Column="2"
Clicked="OnImage2ButtonClicked" />
</Grid>
</Grid>
</ScrollView>
</ContentPage>
and this is its code behind:
public partial class MainPage : ContentPage
{
private readonly Image _image1;
private readonly Image _image2;
public MainPage()
{
InitializeComponent();
_image1 = new Image()
{
Source = ImageSource.FromResource("Surprise.Resources.Images.image1.jpeg"),
VerticalOptions = LayoutOptions.Center,
HeightRequest = 500
};
_image2 = new Image()
{
Source = ImageSource.FromResource("Surprise.Resources.Images.image2.jpg"),
VerticalOptions = LayoutOptions.Center,
HeightRequest = 500
};
}
private void OnImage1ButtonClicked(object sender, EventArgs e)
{
ImageContainer.Children.Clear();
ImageContainer.Children.Add(_image1);
}
private void OnImage2ButtonClicked(object sender, EventArgs e)
{
ImageContainer.Children.Clear();
ImageContainer.Children.Add(_image2);
}
}
On Windows it works correctly.
On Android sometimes the images are loaded in wrong order or even the same image is loaded when I press each button.
Is it a MAUI bug or I'm missing something?
Thanks in advance.
Well, there are some changes that were made with Maui projects, we now have Maui-specific build actions that you can use to specify to your project/solution what the type of a certain file is.
In your Scenario, you should use the MauiImage build action then just uses the name of the file as shown here: https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/image#load-a-local-image should be enough to fix your issue

xamarin.forms ImageSource set from code sometimes disappears, doesnt work on iOS at all

I have this xaml class:
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
HeightRequest="130"
WidthRequest="90"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="InteriorCircle.Pages.MainMenu.CV_PinStyle">
<ContentView.Content>
<StackLayout BackgroundColor="Transparent">
<Frame
HeightRequest="130"
WidthRequest="90"
VerticalOptions="Start"
HasShadow="False"
HorizontalOptions="Start"
BackgroundColor="#565656"
Padding="0"
CornerRadius="25"
IsClippedToBounds="true">
<StackLayout Padding="5">
<Grid VerticalOptions="Center" Margin="10,10,0,0" HorizontalOptions="Center">
<Image x:Name="img_pic"
Margin="3,0,0,0"
HorizontalOptions="Center"
VerticalOptions="Center">
<Image.Clip>
<EllipseGeometry
Center="27,27"
RadiusX="27"
RadiusY="27"/>
</Image.Clip>
</Image>
<Ellipse Stroke="#60CED3"
StrokeThickness="6"
WidthRequest="60"
HeightRequest="60"
HorizontalOptions="Start" />
</Grid>
<Label
Margin="0,0,0,0"
x:Name="label_title"
TextColor="White"
LineBreakMode="TailTruncation"
FontFamily="JakartaReg"
VerticalOptions="Start"
FontSize="12"
HorizontalOptions="Center"/>
<Label
x:Name="label_price"
TextColor="White"
FontFamily="JakartaBold"
VerticalOptions="Start"
FontSize="10"
HorizontalOptions="Center"/>
</StackLayout>
</Frame>
</StackLayout>
</ContentView.Content>
</ContentView>
I retrieve content from another class (event) and set it to the properties from here:
private async Task SetContent(EventType events)
{
InitializeComponent();
byte[] bt = Converters.StringToByteArray(events.eventPictureThumb);
label_title.Text = events.name;
label_price.Text = Converters.GetDecimalPriceFromCents(events.priceInCents) + " €";
Device.BeginInvokeOnMainThread(() =>
{
var source = Converters.ReturnImageSourceFromString(Converters.ByteArrayToString(bt));
img_pic.Source = source;
});
}
However, this does not work sometimes on Android, on iOS not at all.
When I set an image directly in xaml, it is always displayed. On iOS, when the image comes from code, it is never displayed. On Android, it is displayed most of the times, but fails sometimes. When multiple objects load into the view the old ones lose their images.
I am adding the view like so:
var startPin = BitmapDescriptorFactory.FromView(new CV_PinStyle(currentEvent));
Pin pin = new Pin
{
Label = currentEvent.name,
Tag = currentEvent.tblEventID+Constants.DELIMITER+currentEvent.userID,
Icon = startPin,
Type = PinType.Place,
Position = position
};
gMap?.Pins?.Add(pin);
So I am doing somethign wrong here,
can you help me?

Is it possible to show EmptyView after loader(ActivityIndicator) in CarouselView using Xamarin forms?

I have a lot of tried to show EmptyView after Loader but did not get success might i missed some code configuration for the EmptyView and Loader.
I'm using ActivityIndicator loader for the loading view if it will hide once data will come.
Below code is for EmptyView for the CarouselView
<CarouselView.EmptyView>
<Frame BackgroundColor="Transparent" Margin="20,150">
<Frame BackgroundColor="White" CornerRadius="20" HeightRequest="150" WidthRequest="300" HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="Data not Found" FontSize="Medium" HorizontalOptions="Center" VerticalOptions="Center"/>
</Frame>
</Frame>
</CarouselView.EmptyView>
Below code is for ActivityIndicator
<StackLayout IsVisible="{Binding IsBusy}" Padding="12" AbsoluteLayout.LayoutFlags="PositionProportional" AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1">
<ActivityIndicator IsRunning="{Binding IsBusy}" Color="#BFA464" x:Name="PaymentLoader"/>
<Label Text="Data is Loading..." HorizontalOptions="Center" TextColor="#BFA464"/>
</StackLayout>
Below image is my whole code screenshot
here is full code image
If anybody have idea, please share your great and valuable knowledge.
According to your description and code, I guess that you want to display CarouselView's EmptyView and ActivityIndicator when no data found, am I right?
From Xamarin.Forms CarouselView EmptyView, we can see that EmptyView, of type object, the string, binding, or view that will be displayed when the ItemsSource property is null, or when the collection specified by the ItemsSource property is null or empty. The default value is null.
I do one sample that you can take a look:
<StackLayout>
<!-- Place new controls here -->
<CarouselView ItemsSource="{Binding models}">
<CarouselView.EmptyView>
<Frame Margin="20,150" BackgroundColor="Transparent">
<Frame
BackgroundColor="White"
CornerRadius="20"
HeightRequest="150"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="300">
<Label
FontSize="Medium"
HorizontalOptions="Center"
Text="Data not Found"
VerticalOptions="Center" />
</Frame>
</Frame>
</CarouselView.EmptyView>
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame
Margin="8"
BorderColor="Gray"
CornerRadius="20"
HasShadow="True"
HeightRequest="250"
VerticalOptions="CenterAndExpand"
WidthRequest="300">
<StackLayout>
<Image Source="{Binding ImagePath}" />
<Label
FontAttributes="Bold"
FontSize="24"
HorizontalTextAlignment="Center"
Text="{Binding Title}" />
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<StackLayout
Padding="12"
AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1"
AbsoluteLayout.LayoutFlags="PositionProportional"
IsVisible="{Binding IsBusy}">
<ActivityIndicator
x:Name="PaymentLoader"
IsRunning="{Binding IsBusy}"
Color="#BFA464" />
<Label
HorizontalOptions="Center"
Text="Data is Loading..."
TextColor="#BFA464" />
</StackLayout>
</StackLayout>
public partial class MainPage : ContentPage, INotifyPropertyChanged
{
public ObservableCollection<BirdsModel> models { get; set; }
private Boolean _IsBusy;
public Boolean IsBusy
{
get { return _IsBusy; }
set
{
_IsBusy = value;
RaisePropertyChanged("IsBusy");
}
}
public MainPage()
{
InitializeComponent();
IsBusy = true;
models = new ObservableCollection<BirdsModel>();
this.BindingContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
protected override async void OnAppearing()
{
base.OnAppearing();
await Task.Delay(2000);
models.Add(new BirdsModel() { Title = "title 1", ImagePath = "a5.jpg" });
models.Add(new BirdsModel() { Title = "title 2", ImagePath = "a6.jpg" });
models.Add(new BirdsModel() { Title = "title 3", ImagePath = "a7.jpg" });
models.Add(new BirdsModel() { Title = "title 4", ImagePath = "a8.jpg" });
IsBusy = false;
}
}
public class BirdsModel
{
public string Title { get; set; }
public ImageSource ImagePath { get; set; }
}
This is the sample at github, you can take a look:
https://github.com/CherryBu/CarouselViewSample

Xamarin Froms Carousel Page gives Source not Found error while moving to previous Images

Carousel page in Xamarin Forms Working Fine in iOS but in Android working only on "next" Images, But Scrolling Back to Previous Images (which shown before) images gives error "Source not found/ Available" error.
All images loaded from Images Bytes.
Here is my Code. (Source from URL is not working in Some Countries like KSA..)
XAML
<?xml version="1.0" encoding="UTF-8"?>
<CarouselPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" Title=""
x:Class="Prj.XAML.ImageCarouselPg" x:Name="CRV" ItemsSource="{Binding ImageList}" BackgroundColor="{StaticResource primaryLight}" >
<CarouselPage.ItemTemplate >
<DataTemplate >
<ContentPage >
<ContentPage.Padding>
<OnPlatform x:TypeArguments="Thickness">
<On Platform="iOS, Android" Value="0,20,0,0" />
</OnPlatform>
</ContentPage.Padding>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Margin="10,5,10,5" BackgroundColor="{StaticResource primaryLight}">
<!--<Label x:Name="TxtCode" Text="{Binding Code}" HorizontalOptions="Center" HeightRequest="30" TextColor="Black" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" FontSize="Subtitle"/>-->
<Label x:Name="TxtCode" Text="{Binding Code}" HorizontalOptions="Center" HeightRequest="30" TextColor="Black" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" FontSize="Subtitle" FontAttributes="Bold"/>
<Label x:Name="Txtdesc" Text="{Binding Description}" HorizontalOptions="Center" HeightRequest="30" TextColor="Black" HorizontalTextAlignment="Center" VerticalTextAlignment="Center" FontSize="Subtitle"/>
<Image x:Name="img" Source="{Binding BrandImage}" Aspect="AspectFit" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" ></Image>
</StackLayout>
</ContentPage>
</DataTemplate>
</CarouselPage.ItemTemplate>
</CarouselPage>`
Loading Code Back end code
private async void PopulateImageListNew(DataSet dtImgList)
{
string Errstr = ""; string TblName;
try
{
if (dtImgList != null)
{
if (dtImgList.Tables[0].Rows.Count > 0)
{
for (int i = 0; i < dtImgList.Tables[0].Rows.Count; i++)
{
string Code = dtImgList.Tables[0].Rows[i]["Code"].ToString();
string ImageName = dtImgList.Tables[0].Rows[i]["Description"].ToString();
string ImageURL = dtImgList.Tables[0].Rows[i]["ImageUrl"].ToString();
byte[] byteArray = (byte[])(dtImgList.Tables[0].Rows[i]["Image1x"]);
Stream strm = new MemoryStream(byteArray);
Brandimg.Source = ImageSource.FromStream(() => { return strm; });
ImageList.Add(new Models.OurBrands { Code = Code, Description = ImageName,
ImageUrl = ImageURL, BrandImage = Brandimg.Source });
}
}
}
CRV.ItemsSource = ImageList;
//BindingContext = this;
if (CurIdx >= 0)
{
CRV.SelectedItem = ImageList[CurIdx];
}
}
catch (WebException WebEx)
{
WebErrStr = WebEx.Message.ToString();
}
catch (Exception Ex)
{
WebErrStr = Ex.Message.ToString();
}
finally
{
WebErrStr = Errstr;
}
}
Class
public class Brands
{
public string Code { get; set; }
public string Description { get; set; }
public string ImageUrl { get; set; }
public ImageSource BrandImage { get; set; }
public string VideoUrl { get; set; }
}

Tap Gesture Gesture Recognizer in ListView not working

I have this in my ViewModel:
public class MyClass: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int taps = 0;
ICommand tapCommand;
public MyClass()
{
tapCommand = new Command(OnTapped);
}
public ICommand TapCommand
{
get { return tapCommand; }
}
void OnTapped(object s)
{
taps++;
Debug.WriteLine("parameter: " + s);
}
}
and this in the xaml:
<Image Source="delete.jpg" HeightRequest="20" WidthRequest="20">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="Image1" />
</Image.GestureRecognizers>
</Image>
but when the image is clicked nothing appears in output log. What I'm missing ?
Note 1: I've followed the guide here
Note 2: I'm debugging on Android Device
Update 1: full xaml here
You have not provided any code behind, so I had to create my own (see below).
You also would save me 15 minutes if commented out ListView IsEnabled="False"
When you set Command="{Binding TapCommand} the TapCommand corresponds to the TapCommand of the list item, not to the model itself. So, you have 2 options
You can implement click in MyItem (I don't think you want that, so partial code for it commented below in MyItem class)
Define context binding on image itself.
Because of that our view model can be created few times - we don't want that, so the best solution is to define static resource of view model and use it everywhere on page.
The solution is below (you will just need to modify some namespaces and change delte.png to your delete.jpg):
page xml
<?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:ButtonRendererDemo;assembly=ButtonRendererDemo"
x:Class="ButtonRendererDemo.ImageTapComplexPage"
BindingContext="{StaticResource viewModel}">
<ContentPage.Resources>
<ResourceDictionary>
<local:TapComplexViewModel x:Key="viewModel"/>
</ResourceDictionary>
</ContentPage.Resources>
<StackLayout>
<Label Text="text2" VerticalOptions="Center" HorizontalOptions="Center" />
<StackLayout Padding="0,20,0,20">
<Button Text="text" Clicked="onclick" BackgroundColor="#009688"></Button>
</StackLayout>
<Label Text="List Type" VerticalOptions="Center" HorizontalOptions="Center" />
<ListView x:Name="lstItems" RowHeight="60" ItemsSource="{Binding Items}" > <!--IsEnabled="False"-->
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" HorizontalOptions="Fill" Padding="0,2,0,2">
<StackLayout Padding="5,5,5,5">
<Image Source="{Binding source}" HorizontalOptions="End" HeightRequest="40" WidthRequest="40" />
</StackLayout>
<StackLayout Orientation="Vertical" Spacing="1">
<Label Text = "{Binding name}" HeightRequest="20" FontAttributes="Bold"/>
<Label Text = "{Binding data, StringFormat='{0:F0}'}" />
</StackLayout>
<StackLayout HorizontalOptions="EndAndExpand" Padding="0,0,15,0" Orientation="Horizontal">
<Image Source="delete.png" HeightRequest="20" WidthRequest="20">
<Image.GestureRecognizers>
<!--<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="Image1" />-->
<TapGestureRecognizer Command="{Binding Source={StaticResource viewModel}, Path=TapCommand}" CommandParameter="{Binding name}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
Code behind
namespace ButtonRendererDemo
{
public partial class ImageTapComplexPage : ContentPage
{
public ImageTapComplexPage()
{
InitializeComponent();
}
void onclick(object sender, EventArgs args)
{
}
}
public class TapComplexViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int taps = 0;
ICommand tapCommand;
public ObservableCollection<MyItem> Items { get; private set; }
public TapComplexViewModel()
{
Items = new ObservableCollection<MyItem>()
{
new MyItem { name="First", source="Icon.png", data=0.5f },
new MyItem { name="Second", source="Icon.png", data=0.6f },
new MyItem { name="Third", source="Icon.png", data=0.7f }
};
tapCommand = new Command(OnTapped);
}
public ICommand TapCommand
{
get { return tapCommand; }
}
void OnTapped(object s)
{
taps++;
Debug.WriteLine("parameter: " + s);
}
}
public class MyItem
{
public string name { get; set; }
public string source { get; set; }
public float data { get; set; }
//public ICommand TapCommand
//{
// get { return new Command(() => { }); }
//}
}
}
In the back end of the xaml file make sure u set the BindingContext to the view model: Something like this:
xaml.cs
public partial class TapInsideFrameXaml : ContentPage
{
public TapInsideFrameXaml ()
{
InitializeComponent ();
// The TapViewModel contains the TapCommand which is wired up in Xaml
BindingContext = new TapViewModel ();
}
}
Also check:
On Menu > tools > options > debugging > General:
Ensure "Redirect all output window text to the immediate window" is NOT checked
On Project Properties > Build:
Configuration: Debug
"Define DEBUG constant" is checked
"Define TRACE constant" is checked
On the Output window:
Show output from: Debug
Right-click in the output window and ensure "Program output" is checked
Also make sure you are debugging using F5 and not Ctrl f5
You declared the PropertyChangedEvent event but you never actually use it. Try this:
public class MyClass: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
int taps = 0;
ICommand tapCommand;
public MyClass()
{
tapCommand = new Command(OnTapped);
}
public ICommand TapCommand
{
get { return tapCommand; }
}
void OnTapped(object s)
{
taps++;
Debug.WriteLine("parameter: " + s);
OnPropertyChanged();
}
protected virtual void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler (this, new PropertyChangedEventArgs (propertyName));
}
}

Categories

Resources