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.
Related
<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
});
Has anyone implanted something like the following, that could be of relevance to me? How can I put a frame that encompasses both the group and the items in the photo:
click to enlarge
I have a dirty but simple way:
When I make same forms I use ListView without grouping and ViewCell with RepeaterView. You need remember that it is not the best perfomance way.
If you want to design the UI like the screenshot your provided, using frame to crop image, you can take a look:
<CollectionView IsGrouped="true" ItemsSource="{Binding Animals}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Frame Padding="0"
Grid.RowSpan="2"
BorderColor="Black"
CornerRadius="50"
HeightRequest="40"
HorizontalOptions="Center"
IsClippedToBounds="True"
WidthRequest="40">
<Image
Aspect="AspectFill"
HeightRequest="100"
Source="{Binding ImageUrl}"
WidthRequest="100" />
</Frame>
<Label
Grid.Column="1"
FontAttributes="Bold"
Text="{Binding Name}" />
<Label
Grid.Row="1"
Grid.Column="1"
FontAttributes="Italic"
Text="{Binding Location}"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.GroupHeaderTemplate>
<DataTemplate>
<Label
BackgroundColor="LightGray"
FontAttributes="Bold"
FontSize="Large"
Text="{Binding Name}" />
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</CollectionView>
About viewmodel class, you can take a look Xamarin.Forms CollectionView Grouping
I have tried to make all the items in the itemtemplate into a single view as like in the below image, how to achieve this by using Xamarin CarouselView, i am using like this
carousel = new CarouselView();
carousel.BindingContext = this;
carousel.ItemTemplate = itemTemplate;
carousel.SetBinding(CarouselView.ItemsSourceProperty, new Binding(nameof(this.Items), mode: BindingMode.OneWay));
LinearItemsLayout linearItemsLayout = new LinearItemsLayout(ItemsLayoutOrientation.Horizontal);
linearItemsLayout.SnapPointsAlignment = SnapPointsAlignment.Start;
linearItemsLayout.SnapPointsType = SnapPointsType.Mandatory;
carousel.ItemsLayout = linearItemsLayout;
this.Children.Add(carousel,0,1);
Expected UI
The easiest way of doing something like that would be to use the Horizontal CollectionView
CollectionView can display its items in a horizontal list by setting its ItemsLayout property to HorizontalList:
When you check the documents it gives a similar example
<CollectionView ItemsSource="{Binding Monkeys}"
ItemsLayout="HorizontalList">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="140" />
</Grid.ColumnDefinitions>
<Image Grid.RowSpan="2"
Source="{Binding ImageUrl}"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label Grid.Column="1"
Text="{Binding Name}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Location}"
LineBreakMode="TailTruncation"
FontAttributes="Italic"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
Alternatively, this layout can also be accomplished by setting the ItemsLayout property to a LinearItemsLayout object, specifying the Horizontal ItemsLayoutOrientation enumeration member as the Orientation property value:
<CollectionView ItemsSource="{Binding Monkeys}">
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Horizontal" />
</CollectionView.ItemsLayout>
...
</CollectionView>
This results in a single row list, which grows horizontally as new items are added:
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>
We've got an simple collection view for horizontal items. See code below.
<CollectionView ItemsSource="{Binding Items}" ItemsLayout="HorizontalList" ItemSizingStrategy="MeasureFirstItem" HorizontalOptions="StartAndExpand" VerticalOptions="Start" Grid.Row="1">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10">
<Grid.GestureRecognizers>
<TapGestureRecognizer Tapped="Item_Tapped" CommandParameter="{Binding .}"></TapGestureRecognizer>
</Grid.GestureRecognizers>
<Grid.RowDefinitions>
<RowDefinition Height="150" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<Image
Source="{Binding ImageUrl}"
HorizontalOptions="Fill"
VerticalOptions="Fill"
Aspect="AspectFill"
HeightRequest="60"
WidthRequest="60" />
<Label
HorizontalOptions="Center"
Grid.Row="1"
Text="{Binding Title}"
FontAttributes="Bold"
LineBreakMode="TailTruncation" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
On android this works great and I've got items stand neatly next to each other. On iOS the items are overlapping each other. Cannot find why this doesn't work on iOS.