Implementing FlyoutNavigation in my Xamarin.Forms PCL project - c#

I have been searching everywhere on how to implement this IOS platform specific UI component (https://components.xamarin.com/view/flyoutnavigation) in my Xamarin.Forms PCL project, but I have not been able to understand how this would be possible.
I have come upon multiple "Buzz-Words" which I may be able to use, but I am still too new to fully understand what they mean and how I will be able to use them:
Custom Renderers:
With this, I understand that one can customize components available in Xamarin.Forms and create export assemblies in order to "push" platform specific code through to these components from their respective platforms.
Dependency Injection:
With this, I understand that one can create classes, and in the constructor method of those classes, pass through objects that will allow us to incorporate platform-specific code. (How? I have no idea...)
Xamarin.Forms DependencyService:
With this, I understand that we can somehow integrate platform specific code from the shared code (from the portable library class)
Please, I have so many gaps in my knowledge and I am trying so very hard to understand, but I just can't wrap my head around it!
Thanks in advance for your help.

First of All create a xaml page with .cs and give the name as "MenuMasterPage" xaml code
<?xml version="1.0" encoding="UTF-8"?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="TestAppForms.Pages.MenuMasterPage">
<MasterDetailPage.Master>
<ContentPage Icon="hamburger_menu.png" Title="Daily Expense" BackgroundColor="#000000"> <!-- Menu Title background color -->
<StackLayout VerticalOptions="FillAndExpand">
<ListView x:Name="MenuListView" ItemsSource="{Binding MainMenuItems}" ItemSelected="MainMenuItem_Selected" VerticalOptions="FillAndExpand" SeparatorVisibility="None" BackgroundColor="#f5f5f5"> <!-- Menu background color -->
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell Text="{Binding Title}" ImageSource="{Binding Icon}" TextColor="Black"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
</MasterDetailPage>
MenuMasterPage.cs code
public partial class MenuMasterPage : MasterDetailPage
{
public List<MainMenuItem> MainMenuItems { get; set; }
public MenuMasterPage()
{
// Set the binding context to this code behind.
BindingContext = this;
// Build the Menu
MainMenuItems = new List<MainMenuItem>()
{
new MainMenuItem() { Title = "Add Daily Expense", Icon = "menu_inbox.png", TargetType = typeof(Page1) },
new MainMenuItem() { Title = "My Expenses", Icon = "menu_stock.png", TargetType = typeof(Page2) }
};
// Set the default page, this is the "home" page.
Detail = new NavigationPage(new Page1());
InitializeComponent();
}
// When a MenuItem is selected.
public void MainMenuItem_Selected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as MainMenuItem;
if (item != null)
{
if (item.Title.Equals("Add Daily"))
{
Detail = new NavigationPage(new AddDailyExpensePage());
}
else if (item.Title.Equals("My Expenses"))
{
Detail = new NavigationPage(new MyExpensesPage());
}
MenuListView.SelectedItem = null;
IsPresented = false;
}
}
}
public class MainMenuItem
{
public string Title { get; set; }
public Type TargetType { get; set; }
public string Icon { get; set; }
}
In your App.xaml.cs replace the code with this
public App()
{
InitializeComponent();
{
MainPage = new MenuMasterPage();
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}

Can you use the Forms MasterDetail page? https://developer.xamarin.com/guides/xamarin-forms/application-fundamentals/navigation/master-detail-page/

Related

How do I trigger a data refresh on my FlyoutContentTemplate view model when navigating back from my add page?

I am building a Xamarin Forms application using Shell in which I am not building your typical flyout. I have created a template each for the header, footer and content. The content contains data which is fetched from a database.
I'm defining these in my app.xaml file.
<Style TargetType="Shell" ApplyToDerivedTypes="True">
<Setter Property="FlyoutFooterTemplate" Value="{DataTemplate common:FlyoutFooterTemplate}"/>
<Setter Property="FlyoutHeaderTemplate" Value="{DataTemplate common:FlyoutHeaderTemplate}"/>
<Setter Property="FlyoutContentTemplate" Value="{DataTemplate common:FlyoutContentTemplate}"/>
</Style>
I have created the FlyoutContentTemplate as a RefreshView.
<?xml version="1.0" encoding="utf-8" ?>
<RefreshView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:InFlight.ViewModels.Common"
xmlns:model="clr-namespace:InFlight.Core.Models;assembly=InFlight.Core"
x:Class="InFlight.Views.Common.FlyoutContentTemplate"
x:DataType="local:FlyoutContentTemplateViewModel"
Command="{Binding LoadFlightsCommand}"
IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
<CollectionView
ItemsSource="{Binding Flights}"
SelectionMode="None">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:Flight">
<Label Text="{Binding CallSign}"
LineBreakMode="NoWrap"
Style="{StaticResource LabelMedium}" />
<Label Text="{Binding FlightNotes}"
LineBreakMode="NoWrap"
Style="{StaticResource LabelSmall}" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.Footer>
<Button Command="{Binding AddFlightCommand}" Text="Add Flight" />
</CollectionView.Footer>
</CollectionView>
</RefreshView>
The code behind simply sets the BindingContext.
using InFlight.ViewModels.Common;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace InFlight.Views.Common
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class FlyoutContentTemplate : RefreshView
{
readonly FlyoutContentTemplateViewModel viewModel;
public FlyoutContentTemplate()
{
InitializeComponent();
this.BindingContext = viewModel = new FlyoutContentTemplateViewModel();
}
}
}
The view model is fairly simple and handles the LoadFlightsCommand triggered by the RefreshView and the navigation to the AddEditFlightPage.
using InFlight.Core.Models;
using InFlight.Core.Respositories;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace InFlight.ViewModels.Common
{
public class FlyoutContentTemplateViewModel : BaseViewModel
{
public ObservableCollection<Flight> Flights { get; set; }
public Command LoadFlightsCommand { get; }
public Command AddFlightCommand { get; }
readonly IFlightRepository flightRepository;
public FlyoutContentTemplateViewModel()
{
flightRepository = DependencyService.Get<IFlightRepository>();
Flights = new ObservableCollection<Flight>();
LoadFlightsCommand = new Command(ExecuteLoadFlightsCommand);
AddFlightCommand = new Command(async () => await OnAddFlightCommand());
ExecuteLoadFlightsCommand();
}
private async Task OnAddFlightCommand()
{
await Shell.Current.GoToAsync("AddEditFlightPage");
Shell.Current.FlyoutIsPresented = false;
}
private void ExecuteLoadFlightsCommand()
{
IsBusy = true;
try
{
Flights.Clear();
var flts = flightRepository.GetFlights();
foreach (var flight in flts)
{
Flights.Add(flight);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
}
}
This all seems to work well, but at the moment I need to pull to refresh in order to trigger the LoadFlightsCommand.
The issue is that I want to trigger the data refresh when navigating back from my add page. I've seen posts where people tap into the OnAppearing event in order to trigger the refresh, but as I am using a template and refresh view, I don't see how I can do that.
Have I maybe taken the wrong approach and using Shell for a purpose it shouldn't be used for?
I'm thinking that the solution probably involves the events of the shell itself?
Any advice would be much appreciated.
First Approach
I don't have the full picture on how you are defining your Shell's routes/navigation, but I believe what you are trying to achieve could be done using Shell event OnNavigated or OnNavigating.
First thing, Shell (AppShell.xaml.cs) need to have access to the instance of your FlyoutContentTemplateViewModel in roder to call the method ExecuteLoadFlightsCommand() from there.
Turn the accessibility of ExecuteLoadFlightsCommand() to public.
AppShell.xaml.cs
public FlyoutContentTemplateViewModel flyoutContentTemplateViewModel;
public AppShell()
{
flyoutContentTemplateViewModel = new();
InitializeComponent();
}
protected override void OnNavigated(ShellNavigatedEventArgs args)
{
var previousRouteString = args?.Previous?.Location?.OriginalString;
var currentRouteString = args?.Current?.Location?.OriginalString;
if (previousRouteString != null && previousRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]") &&
currentRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]"))
{
flyoutContentTemplate.ExecuteLoadFlightsCommand();
}
base.OnNavigated(args);
}
In your FlyoutContentTemplate(), use the same ViewModel instance from the field that we have added in your AppShell.
public FlyoutContentTemplate()
{
InitializeComponent();
BindingContext = viewModel = (Shell.Current as AppShell).flyoutContentTemplateViewModel;
}
Second Approach
If you don't want to store your VM in your AppShell then you might use DependencyService.
Extract an interface from your FlyoutContentTemplateViewModel: on visual studio select the class name, right click, in the menu click "Quick Actions and refactoring", after that click "Extract interface", VS will generate an interface called IFlyoutContentTemplateViewModel:
public interface IFlyoutContentTemplateViewModel
{
Command AddFlightCommand { get; }
ObservableCollection<Flight> Flights { get; set; }
bool IsBusy { get; }
Command LoadFlightsCommand { get; }
Task OnAddFlightCommand()
void ExecuteLoadFlightsCommand();
}
FlyoutContentTemplate.xaml.cs
public FlyoutContentTemplate()
{
InitializeComponent();
BindingContext = viewModel = new FlyoutContentTemplateViewModel();
DependencyService.RegisterSingleton<IFlyoutContentTemplateViewModel>(viewModel);
}
AppShell.xaml.cs
...
if (previousRouteString != null && previousRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]") &&
currentRouteString.Contains("[DEPENDS ON YOUR ROUTES NAME]"))
{
DependencyService.Resolve<IFlyoutContentTemplateViewModel>()?.ExecuteLoadFlightsCommand();
}
Third Approach
Calling ExecuteLoadFlightsCommand() from OnDisappearing() of AddEditFlightPage, instead of AppShell.OnNavigated().
AddEditFlightPage.xaml.cs
protected override void OnDisappearing()
{
(DependencyService.Resolve<IFlyoutContentTemplateViewModel>())?.ExecuteLoadFlightsCommand();
base.OnDisappearing();
}

How to implement Loading Incrementally (ItemAppearing) Items in ListView using MVVM in Xamarin Forms?

I am having a ListView in which items are added incrementally using ItemAppearing. I want it to implement it through my ViewModel. ItemAppearing only calls a method from View.cs hence, is there any way I could implement it in my ViewModel class.
Please note that I can load incrementally items when adding it from View.cs. I just want to load more items from ViewModel.
Here is my XAML code:
<ListView ItemsSource="{Binding JobsList}" HasUnevenRows="True"
SelectedItem="{Binding SelectedJob}" ItemAppearing="LoadMoreItems">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text="{Binding Title}" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
It would be best if you add (to your question) more details about what you are trying to do.
The following technique blurs the line between "what View does" and "what ViewModel does" - and "tightly couples" your View and your ViewModel - it is possible that there is a better way to approach your goal. Nevertheless, this is a useful technique to know, so I'll show it.
Details for Jason's comment "call your VM method from event handler".
Add a public method to your VM:
public class MyVM
{
public void MyMethod() {
// whatever you need to do to prepare the item.
}
}
In LoadMoreItems, call that method:
((MyVM)BindingContext).MyMethod();
Add parameters as needed.
If you need to "call back" to a method in your View, do that via an action parameter:
public void MyMethod(Action<...> action) {
...
action(...);
}
For more details, google C# passing an Action as a parameter.
There are other techniques for communicating between View and ViewModel - search for more info on that topic.
This answer will be moderately lengthy, but you will not find it anywhere else. I have tried for 2 days.
This answer is lengthy because I have demonstrated 3 things:
Binding ItemAppearing to Command and then incrementally loading items.
Selecting an Item from ListView and displaying it.
Showing animation while loading new items incrementally.
In MVVM, ViewModel is supposed to be ignorant of the View. Hence ViewModel must not know if the ListView inside the View is scrolled to the last item or whether LoadMoreItems should be called on scrolling.
We need to convert ItemAppearing Event to Command and Bind this Command to the ItemAppearing event.
For this purpose we need to install Xamarin.CommunityToolkit Nuget Package. This package is supported by .NetFoundation, Xamarin Community and Microsoft, and is authored by Microsoft. This is the official package and is necessary for most of the advanced Xamarin.Forms. Check more on Nuget.org, Download latest stable release: https://www.nuget.org/packages/Xamarin.CommunityToolkit (Install in all your projects Shared, Android, iOS, UWP, WPF, Tizen, etc)
Assume your Model:
public class Job
{
public int Id { get; set; }
public string Title { get; set; }
}
Now in your XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
...
xmlns:xct="http://xamarin.com/schemas/2020/toolkit">
<StackLayout>
<RefreshView IsRefreshing="{Binding IsLoading}">
<ListView ItemsSource="{Binding JobsList}" SelectedItem="{Binding SelectedJob}">
<ListView.Behaviors>
<xct:EventToCommandBehavior EventName="ItemAppearing"
Command="{Binding LoadMoreItemsCommand}"
CommandParameter="{Binding ItemVisibilityEventArgs}"/>
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Id}" />
<Label Text="{Binding Title}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
In your code behind set BindingContext to instance of the ViewModel
public partial class ListPage : ContentPage
{
ListPageViewModel ListPageVM;
public JobsListPage()
{
InitializeComponent();
ListPageVM = new ListPageViewModel();
BindingContext = ListPageVM;
}
}
In Your ViewModel
public class ListPageViewModel : INotifyPropertyChanged
{
public ObservableCollection<Models.Job> JobsList
{
get { return jobsList; }
set { jobsList = value; OnPropertyChanged(nameof(JobsList)); }
}
public ICommand LoadMoreItemsCommand { get; private set; }
// Used to show Loading Animation in Refresh View
public bool IsLoading
{
get { return isLoading; }
set { isLoading = value; OnPropertyChanged(nameof(IsLoading)); }
}
public Models.Job SelectedJob
{
get { return selectedJob; }
set
{
if (value != null)
{
selectedJob = value;
var page = Application.Current.MainPage;
page.DisplayAlert("Alert", $"Selected: {selectedJob.JobTitle}", "OK");
OnPropertyChanged(nameof(SelectedJob));
}
}
}
ObservableCollection<Models.Job> jobsList;
Models.Job selectedJob;
bool isLoading;
public ListPageViewModel() // ViewModel Constructor
{
// Initialize your List
JobsList = new ObservableCollection<Models.Job>
{
new Models.Job() { Id = 0001, Title = "Product Manager" },
new Models.Job() { Id = 0002, Title = "Senior Executive" },
}
LoadMoreItemsCommand = new Command<ItemVisibilityEventArgs>(
execute: async (ItemVisibilityEventArgs args) =>
{
if ((args.Item as Models.Job).Id >= JobsList[JobsList.Count - 1].Id)
{
IsLoading = true;
for (int i = 0; i < 10; i++)
{
JobsList.Add(new Models.Job()
{
Id = JobsList.Count + 1, JobTitle = JobsList[i].Title
});
}
await System.Threading.Tasks.Task.Delay(2000); // Fake delay
IsLoading = false;
}
});
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

How to bind ListView to a collection and refresh it real time

I am binding my ListView to my Realm database, but it doesn't refresh it when I add a new item into it. I am adding new items using another page.
I am using here as reference: https://help.syncfusion.com/xamarin/sflistview/mvvm#binding-itemssource
My Model:
public class Category : RealmObject
{
[PrimaryKey]
public string CategoryID { get; set; } = Guid.NewGuid().ToString();
public string CategoryTitle { get; set; }
public string CategoryDetails { get; set; }
[Backlink(nameof(Note.CategoryOfNote))]
public IQueryable<Note> Notes { get; }
public string CategoryIcon { get; set; }
public bool IsExpanded { get; set; }
}
My XAML file containing ListView
<ContentPage.BindingContext>
<vm:MainViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="NEWCAT"
Clicked="NewCat_Clicked"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<ListView x:Name="categoryList"
ItemsSource="{Binding Categories}"
ItemTapped="ListView_ItemTapped"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical"
HorizontalOptions="FillAndExpand"
Padding="10"
Spacing="10">
<Label Text="{Binding Path=CategoryTitle}"
FontSize="Medium"/>
<StackLayout IsVisible="{Binding IsExpanded}"
Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Button Text="Notes"
Clicked="NotesButton_Clicked" />
<Button Text="Edit"
Clicked="EditButton_Clicked"/>
<Button Text="Delete"
Clicked="DeleteButton_Clicked"/>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
And my ViewModel
(DBServices.GetCategories is a static method that returns a collection of categories from Realm DB. And BaseViewModel implements INotifyPropertyChanged)
class MainViewModel : BaseViewModel
{
private Category _oldCategory;
public MainViewModel()
{
RefreshCategories();
}
private void RefreshCategories()
{
Categories = new ObservableCollection<Category>(DBServices.GetCategories());
}
private ObservableCollection<Category> _Categories;
public ObservableCollection<Category> Categories
{
get
{
return _Categories;
}
set
{
_Categories = value;
OnPropertyChanged("Categories");
}
}
}
This is OnPropertyChanged method in BaseViewModel class
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
When I click to the toolbar button, it pushes a new form page to create a new category. Then it just adds that category to the Realm DB. Afterwards it pops itself. But I see no change in my ListView.
EDIT: I can see new items in ListView when I restarted the app. But I want it to be listed as I add them.
You could use the Xamarin Forms MessagingCenter to tell the ListView it needs to update.
On the page where the new category is added to the Realm DB, at some point after the category is added but before the page is popped, you would send a message to tell the ListView page to update. This may look something like:
MessagingCenter.Send(this, "Update listview");
In your MainViewModel you'll need to subscribe to the message and then act upon it. This could be something like:
MessagingCenter.Subscribe<AddCategoryPage>(this, "Update listview", (sender) =>
{
RefreshCategories();
});
Two items to note when using the MessagingCenter.
The message passed must be identical between the sender and subscriber. In this case the message is "Update listview". Because it must be identical, you would probably want to define the message in separate class so it can be referenced by both the sender and subscriber.
When subscribing to a message you have to make sure that you unsubscribe. A popular pattern is to subscribe when the page appears and unsubscribe when the page disappears. A different pattern may work better for you though.
On a side note, you shouldn't need the full property definition for Categories. The ObservableCollection will handle the notification when items are added or removed. Just set Categories = new ObservableCollection<Category>(); once and then only add or remove items. You don't need to new it up on every DB call.
To test the XAML and ViewModel only, try replacing DBServices.GetCategories() with the following in the ViewModel:
public static IEnumerable<Category> TestCategories
{
get
{
yield return new Category { CategoryTitle = "title 1" };
yield return new Category { CategoryTitle = "title 2" };
}
}
...
public MainViewModel()
{
Categories = new ObservableCollection<Category>(TestCategories);
}
DBServices.GetCategories() should also be tested for expected output, not shown here.

Do we have to write OnItemTapped method in xml code behind page or ViewModel Page ? and How?

i am trying to add below method in my ViewModel class but showing the error like method not found in code behind page so question is do i have to write the below method in xml code behind page or in viewmodel file , i want to follow MVVM Pattern
ViewModel Page :
public class StationPickerViewModel : ContentPage
{
// private List<StationDetails> _stationDetails;
public List<StationDetails> Stations
{
get
{
return new List<StationDetails>() {
new StationDetails{ Id = 1, StationCode=01, StationFullName="vapi", StationShortName="vp", TrainId=1},
new StationDetails{ Id = 2, StationCode=02, StationFullName="KaramBele", StationShortName="kmb", TrainId=2},
new StationDetails{ Id = 3, StationCode=03, StationFullName="Bhilad", StationShortName="bh", TrainId=3},
new StationDetails{ Id = 4, StationCode=04, StationFullName="Sanjan", StationShortName="sn", TrainId=4},
new StationDetails{ Id = 5, StationCode=05, StationFullName="Umargam", StationShortName="um", TrainId=5}
};
}
}
public void OnItemTapped(object o, ItemTappedEventArgs e)
{
var station = e.Item as StationDetails;
DisplayAlert("Selection Mode", "You Tapped On" + station.StationFullName, "OK");
}
}
xml Page Code :
<?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="RailwayIndicator.View.StationPickerPage">
<ContentPage.Content>
<StackLayout Padding="20">
<Label FontSize="Large">Choose the Starting Station</Label>
<ListView x:Name="StationList"
ItemsSource="Binding Stations"
ItemTapped="OnItemTapped">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="Binding StationFullName" Font="12" BackgroundColor="Brown"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
xml page code behind :
namespace RailwayIndicator.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class StationPickerPage : ContentPage
{
public StationPickerPage ()
{
InitializeComponent ();
}
}
}
First of all, you have multiple issues with your code, for example your ViewModel is inheriting from ContentPage which does not makes any sense.
So please take a look at some MVVM samples out there.
If you want to use MVVM and still have "control" over those events in your ViewModel, you can use EventToCommandBehavior. More about it here and here.
Using EventToCommandBehavior you have the ability and nice way to bind events to some Command in your ViewModel, doing this you are migrating some more code logic from code-behind class which is an good way to respect MVVM even more.
I also recommend you to take a look at docs and learn more about implementing MVVM in your Xamarin.Forms app, here.
Wishing you lots of luck with coding!

How to open another xamarin forms page from clicking a item in a data template list view?

Hello I am working on a app that has multiple xamrian forms pages. my main page consists of items in a data template list view what I need help with is when the user clicks a item in the data template list view it takes them to a different xamrian forms page here's my 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="SchoolTools.SchoolToolsHome">
<ListView x:Name="listView" HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame Padding="0,0,0,8" BackgroundColor="#d2d5d7">
<Frame.Content>
<Frame Padding="15,15,15,15" OutlineColor="Gray" BackgroundColor="White">
<Frame.Content>
<StackLayout Padding="20,0,0,0" Orientation="Horizontal" HorizontalOptions="CenterAndExpand">
<Label Text="{Binding Name}"
FontFamily="OpenSans-Light"
FontSize="24"/>
</StackLayout>
</Frame.Content>
</Frame>
</Frame.Content>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
Here's my code behind:
using System;
using System.Collections.Generic;
using Xamarin.Forms;
namespace AppName
{
public partial class AppName : ContentPage
{
public AppName()
{
InitializeComponent();
var name = new List<Tools>
{
new Tools("netitem","Internet"),
new Tools("emailitem","E-Mail"),
new Tools("mathitem","Math"),
new Tools("sciitem","Science"),
new Tools("writeitem","Handwriting"),
new Tools("carditem","FlashCards"),
new Tools("bookitem","Books"),
};
listView.ItemsSource = name;
Content = listView;
}
}
}
and the tools class:
using System;
namespace AppName
{
public class Tools
{
public string Name { get; private set; }
public string item { get; private set; }
public Tools(string item, string name)
{
this.item = item;
Name = name;
}
public override string ToString()
{
return Name;
}
}
}
I Know there are many examples out there but they are only for one page I need it for multiple pages so any help would be amazing
Thanks in advance!
Typically what I do is I handle OnItemSelected and bind the selected item to a new page. The new page is pushed onto the navigation stack.
void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var tools = e.SelectedItem as Tools;
if (tools == null)
{
return;
}
var toolsView = new ToolsView();
toolsView.BindingContext = tools;
Navigation.PushAsync(toolsView);
}
If the page is different for the tools:
void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var tools = e.SelectedItem as Tools;
if (tools == null)
{
return;
}
ContentPage page = null;
switch (tools.Name)
{
case "Handwriting":
page = new HandwritingView();
break;
case "Books":
page = new BooksView();
break;
default:
page = new ToolsView();
break;
}
page.BindingContext = tools;
Navigation.PushAsync(page);
}

Categories

Resources