How do I bind to MasterPage viewmodel inside a BindableLayout - xamarin

I am trying to bind my Command property to the Command in my MasterDetailPage view model. I tried defining the name property for the master page and setting that as the reference source, but it does not seem to bind to the viewmodel. For context, the List MenuItems is a property in the same Viewmodel and the Title binds just fine. I believe I am not setting the Source for the command correctly, but not sure how to fix it. Also, I am using Prism, so the viewmodel is mapped in app.xaml already.
<MasterDetailPage
x:Class="MasterDetailPrism.Views.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="http://prismlibrary.com"
prism:ViewModelLocator.AutowireViewModel="True"
x:Name="menuMasterPage">
<MasterDetailPage.Master>
<ContentPage Title="Menu">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="225" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackLayout Grid.Row="0" BackgroundColor="Aqua" />
<StackLayout Grid.Row="1" BindableLayout.ItemsSource="{Binding MenuItems}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Button
Command="{Binding NavigateAsync, Source={x:Reference menuMasterPage}}"
CommandParameter="{Binding NavPath}"
Text="{Binding Title}" />
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</Grid>
</ContentPage>
</MasterDetailPage.Master>

I was able to figure it out - I had to name the StackLayout, and then bind to the root of that as the source, not the contentpage or masterpage. In the code below, ItemsList.
<StackLayout Grid.Row="1" BindableLayout.ItemsSource="{Binding MenuItems}" x:Name="ItemsList">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Button
Command="{Binding BindingContext.NavigateAsync, Source={x:Reference ItemsList}}"
CommandParameter="{Binding NavPath}"
Text="{Binding Title}" />
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>

Related

is there CarouselView has event handler about itemselected like listview

<ContentPage.ToolbarItems>
<ToolbarItem Clicked="ToolbarItem_Clicked"
Text="+ Search "
>
</ToolbarItem>
</ContentPage.ToolbarItems>
<StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
</Grid>
<StackLayout Grid.Row="0" >
<CarouselView x:Name="carouselview"
PeekAreaInsets="50"
>
<CarouselView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal"
ItemSpacing="20"
/>
</CarouselView.ItemsLayout>
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Frame HasShadow="True"
BorderColor="DarkGray"
CornerRadius="5"
Margin="20"
HeightRequest="500"
WidthRequest="500"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<StackLayout>
<Label Text="{Binding NameProduct}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Image Source="xamarinremovebg.png"
Aspect="AspectFill"
HeightRequest="150"
WidthRequest="150"
HorizontalOptions="Center" />
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
</StackLayout>
</StackLayout>
This my code I want to use itemselected event in CarouselView.I mean item selected in listview.But there is none in CarouselView.All I want is when I click the item1 in CarouselView i want go to a detail page of item1 thank you so much for helping me.
There is no such a default event like in ListView . However we could add a TapGestureRecognizer on DataTemplate as a workaround .
in xaml
1.set the name of the ContentPage
<?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="xxx.MainPage"
x:Name="page"
>
Add TapGestureRecognizer
<DataTemplate>
<StackLayout>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding ItemSelectedCommand,Source={x:Reference page}}" CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<Frame>
//...
</Frame>
</StackLayout>
</DataTemplate>
in your ViewModel
public ICommand ItemSelectedCommand{ get; set; }
In the constructor:
ItemSelectedCommand= new Command((item)=>{
// item here is type of the model in the ItemSource of CarouselView
// var model = item as yourmodel
});

The property 'Content' is set more than once - XAML

Every time i try to implement <maps:Map IsShowingUser="True" x:Name="Mapa" /> in my mainPage show's "The property 'Content' is set more than once". Every time I put in this place gives me 'The property 'Content' is set more than once'.
If anyone could explain in simple terms where the Content property is set that would be most helpful.
<ContentPage xmlns:maps="clr-namespace:Xamarin.Forms.GoogleMaps;assembly=Xamarin.Forms.GoogleMaps"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="Pap.MainPage">
<maps:Map IsShowingUser="True" x:Name="Mapa" />
<AbsoluteLayout VerticalOptions="FillAndExpand" x:Name="Main">
<StackLayout AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All" x:Name="main" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Image Source="C:\Users\david\Desktop\Pap\Pap\Pap.Android\Resources\drawable\User.png" Aspect="AspectFill" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"></Image>
</StackLayout>
<StackLayout x:Name="body" AbsoluteLayout.LayoutBounds="0,0,1,1" AbsoluteLayout.LayoutFlags="All"
Orientation="Vertical" VerticalOptions="FillAndExpand" Spacing="0">
<!--<StackLayout VerticalOptions="End" BackgroundColor="Red">
<Label Text="Titulo" />
</StackLayout>-->
<StackLayout VerticalOptions="FillAndExpand">
<Label Text="Slider-Example" HorizontalOptions="Center" VerticalOptions="Center"/>
<Image Source="C:\Users\david\Desktop\Pap\Pap\Pap.Android\Resources\drawable\User.png" Aspect="AspectFill"></Image>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="Handle_Tapped">
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
</StackLayout>
</StackLayout>
</AbsoluteLayout>
</ContentPage>
ContentPage has an implicit Content property that can contain a single child element. If you want to include more than one piece of content on your page, you need to use a Layout container, like a StackLayout
<ContentPage ... >
<StackLayout>
... multiple children can go here
</StackLayout>
</ContentPage>
if you were using C# instead of XAML, you would explicitly set the Content property
myPage.Content = new StackLayout{ ... };

How to bind CollectionView.EmptyView to the page's ViewModel?

I'm building an app with a CollectionView, where I'd like the user to add an item to an ObservableCollection when the CollectionView is empty. Problem is: I cannot find out how to bind to the page's ViewModel.
This is a Xamarin.Forms/MvvmCross project
I tried setting the BindingContext, but I didn't succeed.
<CollectionView.EmptyView>
<Grid Padding="24,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="154" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="154" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<pan:PancakeView
CornerRadius="8"
WidthRequest="154"
HeightRequest="154"
IsClippedToBounds="True"
HorizontalOptions="FillAndExpand"
BackgroundColor="#FF252525"
VerticalOptions="FillAndExpand"
Elevation="2">
<pan:PancakeView.HasShadow>
<OnPlatform
x:TypeArguments="x:Boolean"
iOS="False"
Android="True" />
</pan:PancakeView.HasShadow>
<ImageButton
HorizontalOptions="FillAndExpand"
Padding="50"
VerticalOptions="FillAndExpand"
BackgroundColor="#FF252525"
BindingContext="{Binding .}"
Command="{Binding AddPlaylistCommand}"
Source="icon_plus" />
</pan:PancakeView>
</Grid>
</CollectionView.EmptyView>
Command binding doesn't work, I'd like my command to just bind to the page's Viewmodel.
Try this:
<ImageButton
HorizontalOptions="FillAndExpand"
Padding="50"
VerticalOptions="FillAndExpand"
BackgroundColor="#FF252525"
Command="{Binding Source={x:Reference Name=myPage}, Path=BindingContext.DataContext.AddPlaylistCommand}"
Source="icon_plus" />
Where myPage is is the Name of your ContentPage.

partial declartion must not specify different base class in Xamarin

I'm building a Xamarin Crossplatform App
For drawer menu I'm following this tutorial : https://www.youtube.com/watch?v=aYjK0cPjZMQ
But the problem is when I change my MainPage from ContentPage to MasterDetailPage it shows me this error:
MainPage.XAML :
<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Last_MSPL"
x:Class="Last_MSPL.MainPage">
<MasterDetailPage.Master>
<ContentPage Title="Menu">
<Grid BackgroundColor="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="200" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<Image Source="bg.png" Aspect="AspectFill" />
<StackLayout Padding="0,20,0,0" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Image Source="profile.png" Aspect="AspectFill" WidthRequest="85" HeightRequest="85" />
<Label Text="Xam Buddy" TextColor="White" FontSize="Large" />
</StackLayout>
</Grid>
<StackLayout Grid.Row="1" Spacing="15">
<ListView x:Name="navigationDrawerList"
RowHeight="60"
SeparatorVisibility="None"
BackgroundColor="#e8e8e8"
ItemSelected="OnMenuItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!-- Main design for our menu items -->
<StackLayout VerticalOptions="FillAndExpand"
Orientation="Horizontal"
Padding="20,10,0,10"
Spacing="20">
<Image Source="{Binding Icon}"
WidthRequest="40"
HeightRequest="40"
VerticalOptions="Center" />
<Label Text="{Binding Title}"
FontSize="Small"
VerticalOptions="Center"
TextColor="Black"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</Grid>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
Help me through this so I can move forward, Thanks!
I just Clean my project, rebuild and it works
because the generated .g.cs from the xaml has not been refreshed so it was giving this error

Xamarin.Forms Add a GestureRecognizer to an Image in a ListView

I am trying to add a tap gesture to an Image within a ListView
The following Image renders correctly in the ListView without the Image.GestureRecognizers section, but with it, the ListView does not render anything at all (no error message). To clarify this, there is also a Label in the ListView and that does not render either.
<Image x:Name="newsImage" VerticalOptions="End" HeightRequest="200" WidthRequest="200" Aspect="AspectFill" Source="{Binding Imageurllarge}">
<Image.GestureRecognizers>
<TapGestureRecognizer
Tapped="OnTapGestureRecognizerTapped"
NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
</Image>
I took this from - http://developer.xamarin.com/guides/cross-platform/xamarin-forms/working-with/gestures/ (assume this example is for not listview image, but assumed it should work within a listview).
Also (as per comment suggestion)
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding TapCommand}"
CommandParameter="newsImage" />
Does not seem to fair any better.
If anyone has an example of how to add this in the code behind (without a viewmodel is fine) then that will do.
You can use the DataTemplate in the ListView and inside the DataTemplate have a Grid then add the UI elements. In the given sample, I am showing the Name, contact number and Image, I have used the GestureRecognizers on the Image. Try this:
<ListView x:Name="myListView" ItemsSource="{Binding Contacts}" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell Height="75">
<Grid Padding="5">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="80"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Source="user_img.png" Grid.Column="0" Grid.RowSpan="2" VerticalOptions="CenterAndExpand"/>
<Label Grid.Row="0" Grid.Column="1" Font="16" Text="{Binding DisplayName}" LineBreakMode="TailTruncation"></Label>
<Label Grid.Row="1" Grid.Column="1" Font="12" Text="{Binding Number}" LineBreakMode="TailTruncation"></Label>
<Image Grid.Row="0" Grid.RowSpan="3" Grid.Column="2" Source="add.png" Aspect="AspectFill">
<Image.GestureRecognizers>
<TapGestureRecognizer
Command="{Binding AddCommand}"
CommandParameter="{Binding Number}" />
</Image.GestureRecognizers>
</Image>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have had success with TapGestureRecognizer in uses like this one by specifying it in XAML with its own x:Name attribute, then adding a tap handler in code.
Example markup:
<Image.GestureRecognizers>
<TapGestureRecognizer x:Name="tapImage" NumberOfTapsRequired="1" />
</Image.GestureRecognizers>
Then in code something like:
this.tapImage.Tapped += async (object sender, EventArgs e) => {
... // Do whatever is wanted here
}
The handler need not necessarily be marked async, it is just common for my uses that something async is happening in there, like a confirm dialog or scanning a bar code.
You can also attach a gesture recognizer to an image inside a listview. The gesture recognizer can bind to a command in a view model
<ListView x:Name="ExampleList" SeparatorVisibility="None" VerticalOptions="Start" HeightRequest="{Binding HeightRequest}"
HasUnevenRows="True"
CachingStrategy="RecycleElement"
ItemsSource="{Binding FeedItems}"
IsPullToRefreshEnabled="True"
RefreshCommand="{Binding LoadItemsCommand}"
IsRefreshing="{Binding IsBusy, Mode=OneWay}">
<ListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout Orientation="Vertical">
<Label Text="{Binding TimeAgo}" FontSize="8"></Label>
<StackLayout Orientation="Horizontal">
<Image Source="Accept.png" HeightRequest="30" WidthRequest="45" IsVisible="{Binding IsAccepted, Converter={StaticResource inverse}}">
<Image.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={StaticResource sampleViewModel}, Path=AcceptCommand}" CommandParameter="{Binding RequestID}" />
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>

Resources