I have a problem. I created this class that creates an ImageSource collection ObservableCollection<TemplateSource>:
public class TemplateListViewModel
{
public ObservableCollection<TemplateSource> sourceList { get; set; }
public TemplateListViewModel()
{
sourceList = new ObservableCollection<TemplateSource>();
loadingTemplates += onLoadingTemplates;
LoadTemplateList();
}
private event EventHandler loadingTemplates = delegate { };
private void LoadTemplateList()
{
loadingTemplates(this, EventArgs.Empty);
}
private async void onLoadingTemplates(object sender, EventArgs args)
{
List<Template> templateList = await App.RestService.GetTemplates(App.User);
foreach (var template in templateList)
{
ImageSource source = ImageSource.FromUri(new Uri("mysite.org/myapp/" + template.FileName));
TemplateSource templateSource = new TemplateSource { Id = template.Id, Source = source };
sourceList.Add(templateSource);
}
}
}
And in my XAML I use this code:
<ContentPage.Content>
<StackLayout HorizontalOptions="Fill">
<Frame IsClippedToBounds="True" HeightRequest="45" CornerRadius="5" Padding="0" Margin="15,15,15,0" BackgroundColor="Transparent">
<Entry Placeholder="Search" ReturnType="Done" PlaceholderColor="Gray" x:Name="txtSearch" Margin="5,0,0,0" TextColor="White" />
</Frame>
<CollectionView ItemsLayout="HorizontalList" ItemsSource="{Binding sourceList}">
<CollectionView.ItemTemplate>
<DataTemplate>
<ff:CachedImage
Source="{Binding .}"
VerticalOptions="Center"
HorizontalOptions="Fill" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage.Content>
And finally in the page.xaml.cs (code behind):
protected override void OnAppearing()
{
TemplateListViewModel vm = new TemplateListViewModel();
BindingContext = vm;
base.OnAppearing();
}
Now I already got help with this code from #Deczaloth, but he couldn't figure out why the CollectionView stays emtpy after I bind it. Now I already checked, but the sourceList does get filled, so thats not the problem.
What am I doing wrong?
I can see one potential problem in your code XD:
When you bind the Source property of CachedImage you set the binding to ".", but you should instead bind to the Source property of the TemplateSource class (in your context "." means a TemplateSource item!), that is you should change your code like so:
<ff:CachedImage
Source="{Binding Source}"
VerticalOptions="Center"
HorizontalOptions="Fill" />
Related
I have a grouped CollectionView with an ObservableCollection as ItemSource andthe list shows just fine, with the itens grouped. The problem is that the UI does not get updated when i add or remove something from the collection. I need to pop and call the ProductsPage again to see the changes.
I even tried to refresh the entire list by calling the CreateGroups method after a change, it didn't work either.
Here´s parte of the code (i removed some unrelated code so there may be some inconsistencies)
ProdutosGroup
public class ProdutosGroup : ObservableCollection<Produto>
{
public string Titulo { get; set; }
public ProdutosGroup(string titulo, ObservableCollection<Produto> produtos) : base(produtos)
{
Titulo = titulo;
}
}
ProductsViewModel
public ObservableCollection<Produto> Produtos { get; set; } //the actual list of products
public ObservableCollection<ProdutosGroup> ProdutosAgrupadosList { get; set; }//the grouped list
public ListaDeProdutosViewModel(int idListaDeProdutos)
{
PopulateList();
CreateGroups();
}
public void CarregarProdutos()
{
this.Produtos = new ObservableCollection<Produto(App._produtoRepo.GetProdutos);
}
public void CreateGroups()
{
var idsCat = Produtos.Select(x => x.IdCategoria).Distinct();
var cats = new ObservableCollection<ProdutoCategoria>();
foreach (var idCat in idsCat)
{
cats.Add(App._categoriaRepo.GetProdutoCategoriaById(idCat));
}
foreach (var item in cats)
{
ObservableCollection<Produto> produtosDaCategoria = new ObservableCollection<Produto>();
foreach (var prod in Produtos)
{
if (prod.IdCategoria == item.Id)
produtosDaCategoria.Add(prod);
}
ProdutosAgrupadosList.Add(new ProdutosGroup(item.Descricao, new ObservableCollection<Produto>(produtosDaCategoria)));
}
}
ProductsPage
<ContentPage.Content>
<Grid>
<ScrollView >
<CollectionView ItemsSource="{Binding ProdutosAgrupadosList}" x:Name="Listas" IsGrouped="true">
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="models:ProdutosGroup">
<Label Text="{Binding Titulo}" FontSize="28"/>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:Produto">
<Label VerticalTextAlignment="Center" Text="{Binding Nome}" FontSize="28"/>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
<ImageButton Padding="12" Source="BasketPlus" Grid.Row="1" Command="{Binding AddForm}" HorizontalOptions="End" WidthRequest="68" HeightRequest="68" VerticalOptions="End" CornerRadius="100" Margin="0,0,16,22" BackgroundColor="{StaticResource Verde}"/>
</Grid>
</ContentPage.Content>
If you want to add an item in a group, you could simply use the following code:
ProdutosAgrupadosList[0].Add(
new Produto
{
Nome = "and"
}); // this will add the item at the end
or
ProdutosAgrupadosList[0].Insert(1,
new Produto
{
Nome = "and"
}); // add the item after the index1 item
To remove, you could either use ProdutosAgrupadosList[0].RemoveAt(index) or use a SwipeView which you could refer to CollectionView Context menus for more info. A simple demo using SwipeView like the following
<CollectionView.ItemTemplate>
<DataTemplate >
<SwipeView>
<SwipeView.LeftItems>
<SwipeItems>
<SwipeItem Text="Delete"
BackgroundColor="LightPink"
Command="{Binding Source={x:Reference Listas}, Path=BindingContext.DeleteCommand}"
CommandParameter="{Binding}" />
</SwipeItems>
</SwipeView.LeftItems>
<StackLayout>
<Label VerticalTextAlignment="Center" Text="{Binding Nome}" FontSize="28"/>
</StackLayout>
</SwipeView>
</DataTemplate>
</CollectionView.ItemTemplate>
That works for me based on the code in your question. For more info, you could refer to Xamarin.Forms CollectionView
Hope it works for you.
I'm trying to make CollectionView in Shell but it's not updating.
I have one view model connected to Page and AppShell but when I update Collection view only page is updationg.
`public class AppShellViewModel : INotifyPropertyChanged
{
public Command Load { get; }
public ObservableCollection<ListData> _lists { get; set; }
public ObservableCollection<ListData> Lists
{
get { return _lists; }
set
{
_lists = value;
OnPropertyChanged();
}
}
public AppShellViewModel()
{
Lists = new ObservableCollection<ListData>()
{
new ListData(){id=0,name="test",UserId=0},
new ListData(){id=1,name="test1",UserId=1},
new ListData(){id=2,name="test2",UserId=2},
new ListData(){id=3,name="test3",UserId=3},
new ListData(){id=4,name="test4",UserId=4}
};
Load = new Command(async () => await GetUserLists());
}
async Task GetUserLists()
{
for (int i = 5; i < 15; i++)
{
Lists.Add(new ListData {id=i, name=$"test{ i }", UserId=i });
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}`
Then i have App Shell Collection View
`<Shell.FlyoutContent>
<StackLayout BackgroundColor="#34495e">
<Label Text="YOUR LISTS" FontSize="50" />
<CollectionView ItemsSource="{Binding Lists}" >
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:ListData">
<Label Text="{Binding name}"
LineBreakMode="NoWrap"
FontSize="13" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</Shell.FlyoutContent>`
And There is Page CollectionView
`<?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="ToDoApp.Views.AboutPage"
xmlns:model="clr-namespace:ToDoApp.Models">
<StackLayout>
<Button Text="Load" Command="{Binding Load}"/>
<Label Text="{Binding error}"/>
<CollectionView ItemsSource="{Binding Lists}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="10" x:DataType="model:ListData">
<Label Text="{Binding name}"
LineBreakMode="NoWrap"
FontSize="13" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>`
before update it looks like this
Page before update
Shell before update
And after update the only what changed is content page and shell is the same as before
Page after update
Shell after update
Related to Jason's comment.
WON'T CHANGE TOGETHER
NOT the same instance - BindingContexts similar to these:
// In AppShell.xaml.cs.
public AppShell()
{
InitializeComponent();
BindingContext = new AppShellViewModel();
}
// In AboutPage.xaml.cs.
public AboutPage()
{
InitializeComponent();
BindingContext = new AppShellViewModel();
}
GOOD (SHARED BETWEEN TWO PLACES)
BindingContexts are SAME instance:
// In AppShellViewModel.cs.
public class AppShellViewModel ...
{
private static AppShellViewModel _it;
public static AppShellViewModel It
{
get {
if (_it == null)
_it = new AppShellViewModel();
return _it;
}
}
}
// In AppShell.xaml.cs.
public AppShell()
{
InitializeComponent();
BindingContext = AppShellViewModel.It;
}
// In AboutPage.xaml.cs.
public AboutPage()
{
InitializeComponent();
BindingContext = AppShellViewModel.It;
}
I want to create an application that can Create, Read, Update and Delete Merchandiser records.
I am struggling with how to "Update" and "Delete" a record based on a ItemSelected in the ListView.
The item selected in the ListView represents a Merchandiser and is currently being passed into each new View as an argument.
I intend to store data in an SQLite database, but for simplicity have not included any of that logic. Database Commands (Save, Delete etc.) will be created in the MerchandiserViewModel
Here is my slimmed down code so far
Merchandiser.cs Model
public class Merchandiser
{
public string Name { get; set; }
public string PhoneNumber { get; set; }
// Additional Properties not shown for simplicity
}
MerchandiserViewModel.cs ViewModel
public class MerchandiserViewModel : ViewModelBase
{
public ObservableCollection<Merchandiser> MerchandiserList { get; set; }
private Merchandiser selectedItem;
public Merchandiser SelectedItem
{
get { return selectedItem; }
set
{
selectedItem = value;
RaisePropertyChanged();
}
}
public MerchandiserViewModel()
{
MerchandiserList = new ObservableCollection<Merchandiser>();
CreateData();
}
private void CreateData()
{
for (int i = 0; i < 20; i++)
{
Merchandiser merchandiser = new Merchandiser();
merchandiser.Name = $"Merchandiser {i}";
merchandiser.PhoneNumber = $"12{i}6{i*3}{i*8}{i*9/3+2}";
MerchandiserList.Add(merchandiser);
}
}
}
// Database commands and other logic not shown...
}
BaseViewModel.cs
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
MerchandiserListPage.xaml & .cs View - Display List of Merchandiers
<?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="MVVM.Views.MerchandisersListPage">
<ContentPage.Content>
<StackLayout>
<ListView x:Name="MerchandiserListView"
ItemSelected="MerchandiserListView_ItemSelected"
SelectionMode="Single"
HasUnevenRows="True"
ItemsSource="{Binding MerchandiserList}"
SelectedItem="{Binding SelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
<Label
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
// MerchandisersListPage.xaml.cs - Code Behind
public MerchandisersListPage()
{
InitializeComponent();
this.BindingContext = new MerchandiserViewModel();
}
private async void MerchandiserListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
Merchandiser merchandiser = (Merchandiser)e.SelectedItem;
await Navigation.PushAsync(new MerchandisersProfilePage(merchandiser));
}
MerchandisersProfilePage.xaml & .cs
This page should navigate to the MerchandiserEditPage using an Edit Button but I'm not sure if I am handling the 'Code Behind' correctly?
<?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="MVVM.Views.MerchandisersProfilePage">
<ContentPage.Content>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name: " />
<Label
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="PhoneNumber: " />
<Label
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
<Button Text="Edit"
Clicked="EditButton_Clicked"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
// MerchandisersProfilePage.xaml.cs - Code Behind
Merchandiser selectedMerchandiser;
public MerchandisersProfilePage(Merchandiser merchandiser)
{
InitializeComponent();
selectedMerchandiser = merchandiser; // Is this what I should be doing?
this.BindingContext = merchandiser;
}
private async void EditButton_Clicked(object sender, EventArgs e)
{
// Am I doing this the correct way??
await Navigation.PushAsync(new MerchandiserEditPage(selectedMerchandiser));
}
MerchandiserEditPage.xaml & .cs This is where I am stuck.
I will need to update the record in the database by calling a method in the MerchandiserViewModel but am not sure how to do this? The method (which ideally should be called by a Command) to update the database has the following signature UpdateMerchandiser(Merchandiser merchandiser).
Ideally I would like the Save Button to use a Command instead of Clicked so I can access the Save command in the MerchandiserViewModel but this imposes another problem around form validation. How then can I then validate this information (e.g. Name is not empty) before saving it the the database? Because the MerchandiserViewModel doesn't know anything about the MerchandiserEditPage.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="MVVM.Views.MerchandiserEditPage">
<ContentPage.Content>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name: " />
<Entry
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="PhoneNumber: " />
<Entry
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
<!-- Ideally this should use 'Command' instead of 'Clicked' -->
<Button Text="Save"
Clicked="SaveButton_Clicked"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
// MerchandiserEditPage.xaml.cs - Code Behind
public MerchandiserEditPage(Merchandiser merchandiser)
{
InitializeComponent();
this.BindingContext = merchandiser;
}
// I would prefer not to use an event handler but use a Command in the MerchandiserViewModel instead
// I also need to perform some basic validation e.g. Name entry should not be empty etc.
private async void SaveButton_Clicked(object sender, EventArgs e)
{
// How can I Save/Update the changes?
// Pop() page off the stack and return to the MerchandiserProfileView
await Navigation.PopAsync();
}
I believe the above code is designed in accordance to MVVM, however if not, please advise where I am violating this pattern?
I also want to do similar for deleting a record but once I get the update method sorted I'm sure deleting will follow similar logic.
Note: The code above is not shown in its entirety and is missing SQLite database functionality and other logic for simplicity. All functionality to the database (Save, Update, Delete) is in the MerchandiserViewModel. I will edit or add any additional information to this question as required to help provide a complete picture of the problem.
Should ViewModels inherit other ViewModels?
I have a MerchandiserViewModel that contains the basic properties and database functions for a Merchandiser model.
The MerchandiserViewModel has a SelectedMerchandiser property that holds the selected Merchandiser from the ItemSelected in a ListView
MerchandiserViewModel.cs
public MerchandiserViewModel : INotifyPropertyChanged
{
// Property to hold the selected Merchandiser
// Generally I would make this static but then I can't bind the property
public Merchandiser SelectedMerchandiser {get; set;}
// Other logic...
}
The MerchandiserViewModel is instantiated as a Static Resource in App.xaml so that I only have one instance of the view model.
App.xaml
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MobileApp.App"
xmlns:ViewModels="clr-namespace:MobileApp.ViewModels">
<Application.Resources>
<ViewModels:MerchandiserViewModel x:Key="MerchandiserViewModel" />
<ViewModels:MerchandiserProfileViewModel x:Key="MerchandiserProfileViewModel" />
</Application.Resources>
</Application>
For each View related to a Merchandiser e.g. MerchandiserProfile, EditProfile etc. I create a new ViewModel and inherit the MerchandiserViewModel
MerchandiserProfileViewModel.cs inherits the MerchandiserViewModel
public class MerchandiserProfileViewModel : MerchandiserViewModel
{
// Logic Specific to the Merchandiser Profile View
}
The problem is... when I create a new [Page]ViewModel and inherit the "MerchandiserViewModel" I receive the following error message.
I think this may be because a new instance of the MerchandiserViewModel is created so I am not referencing the initial SelectedMerchandiser property.
This makes me think that inheriting ViewModels isn't a good idea?
How is this situation usually handled? Should I just jam all logic for each page/view into the one MerchandiserViewModel? I want my code to be as clean an separated as possible, so would like to avoid this if possible.
AFTER THOUGHT
Am I able to access the properties of the MerchandiserViewModel in static Resource in C#? this way I could pass the required properties to the new ViewModel without inheriting the MerchandiserViewModel ... keen to hear thoughts on this?
The MerchandiserViewModel has a SelectedMerchandiser property that holds the selected Merchandiser from the ItemSelected in a ListView
According to your description, you want to binding for ListView, for MerchandiserViewModel, you don't need to inherit other ViewModels, I suggest you can take a look the Model-View-ViewModel Pattern
I do one sample that binding ListView using MVVM, please take a look.
<StackLayout>
<ListView
x:Name="listview1"
HasUnevenRows="True"
ItemsSource="{Binding mers}"
SelectedItem="{Binding selecteditem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
<Label
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
The model class,contains some properties that binding to UI.
public class Merchandiser
{
public string Name { get; set; }
public string PhoneNumber { get; set; }
}
The MerchandiserViewmodel class, the view model implements properties and commands to which the view can data bind to, and notifies the view of any state changes through change notification events. The properties and commands that the view model provides define the functionality to be offered by the UI, but the view determines how that functionality is to be displayed.
public class MerchandiserViewmodel:ViewModelBase
{
public ObservableCollection<Merchandiser> mers { get; set; }
private Merchandiser _selecteditem;
public Merchandiser selecteditem
{
get { return _selecteditem; }
set
{
_selecteditem = value;
RaisePropertyChanged("selecteditem");
}
}
public MerchandiserViewmodel()
{
mers = new ObservableCollection<Merchandiser>();
getdata();
}
private void getdata()
{
for(int i=0;i<20;i++)
{
Merchandiser mer = new Merchandiser();
mer.Name = "merchandiser "+i;
mer.PhoneNumber = "123";
mers.Add(mer);
}
}
}
The ViewModelBase is class that implementinf INotifyPropertyChanged interface, notify data changed. For MerchandiserViewmodel, the Selected Merchandiser(selecteditem) must implement INotifyPropertyChanged to notify data change when you selected item from ListView every time.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Binding ViewModel to ContentPage
public partial class Page10 : ContentPage
{
public Page10()
{
InitializeComponent();
this.BindingContext = new MerchandiserViewmodel();
}
}
Update:
If you want to navigate to detailed page when select ListView item, you can use constructor pass by value in ListView_ItemSelected event.
<StackLayout>
<ListView
x:Name="listview1" ItemSelected="listview1_ItemSelected" SelectionMode="Single"
HasUnevenRows="True"
ItemsSource="{Binding mers}"
SelectedItem="{Binding selecteditem}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
<Label
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
private async void listview1_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
Merchandiser item = (Merchandiser)e.SelectedItem;
await Navigation.PushAsync(new simplecontrol.Page29(item));
}
Detailed Page:
<ContentPage.Content>
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name: " />
<Label
FontSize="Large"
Text="{Binding Name}"
VerticalOptions="Center" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="PhoneNumber: " />
<Label
FontSize="Small"
Text="{Binding PhoneNumber}"
VerticalOptions="Center" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
public partial class Page29 : ContentPage
{
public Page29(Merchandiser mer)
{
InitializeComponent();
this.BindingContext = mer;
}
}
I have masterdetailpage that have Logout function inside that (so instead navigating to other page it will shows display alert), but i dont know how to insert the logout method inside the masterdetailpage, i already tried using ICommand but seem it didnt works and make my application force close .
Here is my MasterPageItem Model
public class MasterPageItem
{
public string Title { get; set; }
public string Icon { get; set; }
public Type TargetType { get; set; }
public ICommand Commando { get; set; }
}
here is the listview for MasterDetailPage
<ListView x:Name="navigationDrawerList"
RowHeight="45"
SeparatorVisibility="None"
BackgroundColor="#000000"
ItemSelected="OnMenuItemSelected">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<!-- Main design for our menu items -->
<StackLayout BackgroundColor="#000000" VerticalOptions="FillAndExpand"
Orientation="Horizontal"
Padding="20,10,0,10"
Spacing="20">
<Image Source="{Binding Icon}"
WidthRequest="60"
HeightRequest="60"
VerticalOptions="Center" />
<Label FontFamily="Panton-LightCaps.otf#Panton-LightCaps" Text="{Binding Title}"
FontSize="Medium"
VerticalOptions="Center"
TextColor="White"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and i tried to insert the method like this
public ICommand GetOff { get; private set; }
public MainPage()
{
GetOff = new Command(LogoutCommand)
var page9 = new MasterPageItem() { Title = "LOGOUT", Commando = GetOff };
}
public async void LogoutCommand ()
{
var result = await this.DisplayAlert("Alert!", "Do you really want to exit?", "Yes", "No");
if (result == true)
{
App.AuthenticationClient.UserTokenCache.Clear(Constants.ApplicationID);
Application.Current.MainPage = new NavigationPage(new NewPageLogin());
}
}
Is there another way to insert method inside MasterdetailPage ? Any suggestion would be appreciated
Option 1
You can add a footer to your listview and attach a tap gesture recognizer to it, like this:
<ListView.Footer>
<StackLayout BackgroundColor="#000000"
VerticalOptions="FillAndExpand"
Orientation="Horizontal"
Padding="20,10,0,10"
Spacing="20">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding LogoutCommand}" />
</StackLayout.GestureRecognizers>
<Image Source="YourIcon"
WidthRequest="60"
HeightRequest="60"
VerticalOptions="Center" />
<Label FontFamily="Panton-LightCaps.otf#Panton-LightCaps"
Text="{Binding Title}"
FontSize="Medium"
VerticalOptions="Center"
TextColor="White"/>
</StackLayout>
</ListView.Footer>
It should go inside the ListView tag.
As you see, it supports Command, so you can use the one you already have.
Option 2
You can set the TargetType of your sign out item to null and do something like this:
private void OnMenuItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as MasterPageItem;
if (item == null)
return;
// Check if sign out was tapped
if (item.TargetType != null)
{
var page = (Page)Activator.CreateInstance(item.TargetType);
page.Title = item.Title;
Detail = new NavigationPage(page);
IsPresented = false;
}
else
{
// Manage your sign out action
var result = await this.DisplayAlert("Alert!", "Do you really want to exit?", "Yes", "No");
if (result == true)
{
App.AuthenticationClient.UserTokenCache.Clear(Constants.ApplicationID);
Application.Current.MainPage = new NavigationPage(new NewPageLogin());
}
}
}