I'm looking for a more reliable option in Xamarin - c#

I dont know how is it called.
I need to create something that works this way:
Do button, when you click button under button you have list and you can choos one option. List should be button's width.
You can find it in aplication to choose for example language of country.
Do Xamarin built-in something to create this? Or can someone show me how implement this?

Or you could roll your own in Forms, something like:
ImagePickerDropDown.xaml:
<?xml version="1.0" encoding="UTF-8"?>
<ContentView
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ImagePickerDropdownSample.ImagePickerDropdown"
x:Name="imagePickerDropDown" >
<ContentView.Content>
<StackLayout>
<ImageButton x:Name="mainButton"
Source="{Binding Source={x:Reference imagePickerDropDown}, Path=SelectedImage}"
Clicked="ImageClicked" />
<StackLayout x:Name="stackView"
BindableLayout.ItemsSource="{Binding Source={x:Reference imagePickerDropDown}, Path=Images}"
IsVisible="False">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<ImageButton Source="{Binding .}" Clicked="ImageSelected"/>
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>
ImagePickerDropDown.xaml.cs:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Xamarin.Forms;
namespace ImagePickerDropdownSample
{
public partial class ImagePickerDropdown : ContentView
{
public ImagePickerDropdown()
{
InitializeComponent();
}
private void ImageSelected(object sender, EventArgs e)
{
var imageSource = (sender as ImageButton).Source;
SelectedImage = imageSource;
mainButton.IsEnabled = true;
stackView.IsVisible = false;
}
private void ImageClicked(object sender, EventArgs e)
{
mainButton.IsEnabled = false;
stackView.IsVisible = true;
}
public static readonly BindableProperty SelectedImageProperty =
BindableProperty.Create(nameof(SelectedImage), typeof(ImageSource), typeof(ImagePickerDropdown), null);
public ImageSource SelectedImage
{
get
{
return (ImageSource)GetValue(SelectedImageProperty);
}
set
{
SetValue(SelectedImageProperty, value);
}
}
public static readonly BindableProperty ImagesProperty =
BindableProperty.Create(nameof(Images), typeof(ObservableCollection<ImageSource>), typeof(ImagePickerDropdown), null);
public ObservableCollection<ImageSource> Images
{
get
{
return (ObservableCollection<ImageSource>)GetValue(ImagesProperty);
}
set
{
SetValue(ImagesProperty, value);
}
}
}
}
Using it 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"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="ImagePickerDropdownSample.MainPage"
xmlns:local="clr-namespace:ImagePickerDropdownSample"
Padding="0,50,0,0"
BackgroundColor="Black">
<StackLayout
x:Name="mainLayout">
<Label Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="Start"
TextColor="White"/>
<local:ImagePickerDropdown SelectedImage="{Binding SelectedImage}"
Images="{Binding Images}"
WidthRequest="50"
HorizontalOptions="Center"
BackgroundColor="Black"/>
</StackLayout>
</ContentPage>
Using it code behind:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace ImagePickerDropdownSample
{
// Learn more about making custom code visible in the Xamarin.Forms previewer
// by visiting https://aka.ms/xamarinforms-previewer
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
Images = new ObservableCollection<ImageSource>();
Images.Add(new FileImageSource() { File = "image1.png" });
Images.Add(new FileImageSource() { File = "image2.png" });
Images.Add(new FileImageSource() { File = "image3.png" });
SelectedImage = Images[0];
BindingContext = this;
}
ImageSource _selectedImage;
public ImageSource SelectedImage
{
get
{
return _selectedImage;
}
set
{
if (_selectedImage != value)
{
_selectedImage = value;
OnPropertyChanged(nameof(SelectedImage));
}
}
}
ObservableCollection<ImageSource> _images;
public ObservableCollection<ImageSource> Images
{
get
{
return _images;
}
set
{
if (_images != value)
{
_images = value;
OnPropertyChanged(nameof(Images));
}
}
}
}
}

Use a Spinner .. basically you need to first create an ArrayAdapter then attach the ArrayAdapter to a Spinner :
//we need a List of some type because the ArrayAdapter takes one as param
var items = new List<string>() {"one", "two", "three"};
//instantiate the ArrayAdapter with context, your Resource is a layout, items is the List
var adapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleSpinnerItem, items);
//then instantiate your spinner
var spinner = FindViewById<Spinner>(Resource.Id.spinner);
//and attach the adapter to the spinner like this
spinner.Adapter = adapter;
from #Aaron He
Create android spinner dynamically in Xamarin

Related

How do I use Xamarin.Essentials MediaPicker with MVVM and DataBinding

I am trying to capture a photo in my app and as this needs to be implemented on different pages I need it to work within MVVM architecture. It works perfectly fine when I test it on the Camera page code behind, but as soon as I implement DataBinding and MVVM, the Emulator camera fails to initialize. I don't get any build or deployment errors and have no idea where to start looking. The documentation isn't much help. The images captured needs to be saved and reused each time the app is opened - something to keep in mind perhaps.
Here is my ViewModel:
using System.Collections.Generic;
using System.Text;
using Xamarin.Essentials;
using Xamarin.Forms;
using XamCam.Views;
using MvvmHelpers;
using System.ComponentModel;
using System.Windows.Input;
namespace XamCam.ViewModels
{
public class CameraViewModels : BaseViewModel
{
public CameraViewModels()
{
TakePhoto = new Command(OnTakePhoto);
}
public ICommand TakePhoto { get; }
private Image image; // = new Image();
public Image CamImage
{
get => image;
set
{
if (image == value)
return;
image = value;
OnPropertyChanged();
}
}
async void OnTakePhoto()
{
var result = await MediaPicker.CapturePhotoAsync();
if (result != null)
{
var stream = await result.OpenReadAsync();
image.Source = ImageSource.FromStream(() => stream);
}
}
}
}
This is my View 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"
xmlns:viewmodels="clr-namespace:XamCam.ViewModels"
x:DataType="viewmodels:CameraViewModels"
x:Class="XamCam.Views.Camera"
BackgroundColor="AliceBlue">
<ContentPage.BindingContext>
<viewmodels:CameraViewModels/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout BindingContext="CameraViewModel">
<Label Text="Welcome to The XamCam!" />
<Button Text="Take Photo"
Command="{Binding TakePhoto}"/>
<Image BindingContext="{Binding CamImage}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
I suspect that it has something to do with my CamImage property but I am very new to this and I am not sure if this is the correct way to bind a media object.
I suspect that it has something to do with my CamImage property but I am very new to this and I am not sure if this is the correct way to bind a media object.
I suggest you can add ImageSource1 property, not Image property in CameraViewModels.
public class CameraViewModels : INotifyPropertyChanged
{
public CameraViewModels()
{
TakePhoto = new Command(OnTakePhoto);
}
public ICommand TakePhoto { get; }
private ImageSource image;
public ImageSource CamImage
{
get => image;
set
{
if (image == value)
return;
image = value;
RaisePropertyChanged("CamImage");
}
}
async void OnTakePhoto()
{
var result = await Xamarin.Essentials.MediaPicker.CapturePhotoAsync();
if (result != null)
{
var stream = await result.OpenReadAsync();
CamImage = ImageSource.FromStream(() => stream);
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
<ContentPage
x:Class="App1.MainPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:App1">
<ContentPage.BindingContext>
<local:CameraViewModels />
</ContentPage.BindingContext>
<StackLayout>
<StackLayout>
<Label Text="Welcome to The XamCam!" />
<Button Command="{Binding TakePhoto}" Text="Take Photo" />
<Image Source="{Binding CamImage}" />
</StackLayout>
</StackLayout>

Why won't changes reflect in my Xamarin.Forms project or SQLite database

UPDATE - Issue #1 is Solved, Issue#2 is still unsolved
You can view a very crude demonstration video of my issue at https://www.youtube.com/watch?v=5_6KJ0QJouM
I am building have a Xamarin.Forms app with an SQLite database using the MVVM design pattern and C#
When try to Save a record to the database from a View the update/save does not appear to be saving to the SQLite database or reflect in other Views.
I know the database Save method does work as I have created some dummy data when the application first loads (in App.xaml.cs) using the DeveloperData.cs file.
I have two issues.
(SOLVED) Issue 1 - Data not Saving to Database
when I call the Save command from the MerchandiserEditPage.xaml, which uses the MerchandiserEditPageViewModel.cs ViewModel, the record does not appear to save.
Issue 2 - Changes Reflecting in other Views
Once the updated data is saved to the database, how can I reflect that change in other views? After I Save a record from the MerchandiserEditPage that View is "Popped" off the stack and the user is returned to the MerchandiserProfileView. I want the updated data to be reflected in all other views on the stack. But this doesn't appear to be happening? (I tested this using hardcoded data and the same issue occurred, so problem is not directly related to issue 1)
There are many files in my project, that can be viewed/downloaded from my GitHub repository but I will concentrate on the following in this question.
MerchandiserEditPage.xaml (View)
MerchandiserProfilePage.xaml (View)
MerchandiserDatabase.cs (Database Functions)x
MerchandiserEditPageViewModel.cs x
View my GitHub repository for the full project.
MerchandiserDatabase.cs (Database Functions)
using SQLite;
namespace MobileApp.Database
{
public class MerchandiserDatabase
{
private static SQLiteConnection database = DependencyService.Get<IDatabaseConnection>().DbConnection();
private readonly static object collisionLock = new object();
public MerchandiserDatabase()
{
database.CreateTable<Models.Merchandiser>();
}
public static void SaveMerchandiser(Models.Merchandiser merchandiser)
{
lock (collisionLock)
{
if (merchandiser.Id != 0)
{
database.Update(merchandiser);
}
else
{
database.Insert(merchandiser);
}
}
}
}
}
MerchandiserEditPageViewModel.cs (ViewModel) UPDATED
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace MobileApp.ViewModels
{
public class MerchandiserEditPageViewModel : BaseViewModel
{
public string PageTitle { get; } = "Edit Merchandiser Profile";
public Command SaveCommand { get; set; }
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged();
}
}
private string phone;
public string Phone
{
get { return phone; }
set
{
phone = value;
OnPropertyChanged();
}
}
private string email;
public string Email
{
get { return email; }
set
{
email = value;
OnPropertyChanged();
}
}
public MerchandiserEditPageViewModel(Models.Merchandiser selectedMerchandiser)
{
Name = selectedMerchandiser.Name;
Phone = selectedMerchandiser.Phone;
Email = selectedMerchandiser.Email;
SaveCommand = new Command( async ()=> {
selectedMerchandiser.Name = this.Name;
selectedMerchandiser.Phone = this.Phone;
selectedMerchandiser.Email = this.Email;
Database.MerchandiserDatabase.SaveMerchandiser(selectedMerchandiser);
await Application.Current.MainPage.Navigation.PopModalAsync();
});
}
}
}
MerchandiserEditPage.xaml (View)
<?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="MobileApp.Views.MerchandiserEditPage">
<ContentPage.Content>
<StackLayout>
<!--Page Heading-->
<StackLayout Spacing="0">
<Label Text="{Binding PageTitle}"
Style="{StaticResource PageTitle}"/>
<BoxView HeightRequest="1" Color="LightGray" />
</StackLayout>
<!-- Merchandiser Profile -->
<StackLayout Margin="10">
<Label Text="Name"/>
<Entry Text="{Binding Name}"/>
<Label Text="Phone"/>
<Entry Text="{Binding Phone}"/>
<Label Text="Email"/>
<Entry Text="{Binding Email}"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="Center">
<Button Text="Cancel"
Clicked="CancelButton_Clicked"/>
<Button Text="Save"
Command="{Binding SaveCommand}"/>
</StackLayout>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
MerchandiserEditPage.xaml.cs (View - Code Behind)
public partial class MerchandiserEditPage : ContentPage
{
Models.Merchandiser SelectedMerchandiser { get; set; }
public MerchandiserEditPage (Models.Merchandiser selectedMerchandiser)
{
InitializeComponent ();
SelectedMerchandiser = selectedMerchandiser;
this.BindingContext = new ViewModels.MerchandiserEditPageViewModel(selectedMerchandiser);
}
async private void CancelButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
}
MerchandiserProfilePage.xaml (View - 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="MobileApp.Views.MerchandiserProfilePage"
NavigationPage.HasNavigationBar="False">
<ContentPage.Content>
<StackLayout>
<!--Page Heading-->
<StackLayout Spacing="0">
<Label Text="{Binding PageTitle}"
Style="{StaticResource PageTitle}"/>
<BoxView HeightRequest="1" Color="LightGray" />
</StackLayout>
<!-- Merchandiser Profile -->
<StackLayout Margin="10">
<Label Text="Name"/>
<Entry Text="{Binding Name}"
IsEnabled="False"/>
<Label Text="Phone"/>
<Entry Text="{Binding Phone}"
IsEnabled="False"/>
<Label Text="Email"/>
<Entry Text="{Binding Email}"
IsEnabled="False"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="Center">
<Button Text="Back"
Clicked="BackButton_Clicked"/>
<Button Text="Edit"
Clicked="EditButton_Clicked"/>
</StackLayout>
<Button Text="Delete"
Command="{Binding DeleteCommand}"/>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
MerchandiserProfilePage.xaml.cs - (View - Code Behind)
public partial class MerchandiserProfilePage : ContentPage
{
private Models.Merchandiser SelectedMerchandister { get; set; }
public MerchandiserProfilePage (Models.Merchandiser selectedMerchandiser)
{
InitializeComponent ();
SelectedMerchandister = selectedMerchandiser;
this.BindingContext = new ViewModels.MerchandiserProfilePageViewModel(selectedMerchandiser);
}
async private void BackButton_Clicked(object sender, EventArgs e)
{
await Navigation.PopModalAsync();
}
async private void EditButton_Clicked(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new Views.MerchandiserEditPage(SelectedMerchandister));
}
}
MerchandiserProfilePageViewModel.cs (ViewModel)
using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;
namespace MobileApp.ViewModels
{
public class MerchandiserProfilePageViewModel : BaseViewModel
{
public string PageTitle { get; } = "Merchandiser Profile";
public Command DeleteCommand { get; }
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged();
}
}
private string phone;
public string Phone
{
get { return phone; }
set
{
phone = value;
OnPropertyChanged();
}
}
private string email;
public string Email
{
get { return email; }
set
{
email = value;
OnPropertyChanged();
}
}
public MerchandiserProfilePageViewModel(Models.Merchandiser selectedMerchandiser)
{
Name = selectedMerchandiser.Name;
Phone = selectedMerchandiser.Phone;
Email = selectedMerchandiser.Email;
DeleteCommand = new Command( async()=> {
bool deleteConfirmed = await Application.Current.MainPage.DisplayAlert("Confirm Delete",$"Are you sure you want to delete {selectedMerchandiser.Name} as a Merchandiser?","Yes","No");
if (deleteConfirmed)
{
// TODO: Delete Merchandiser
await Application.Current.MainPage.Navigation.PopModalAsync();
}
});
}
}
}
you have a hardcoded set of data in your VM instead of loading it from the db
public MerchandisersPageViewModel()
{
//Merchandisers = new ObservableCollection<Models.Merchandiser>(Database.MerchandiserDatabase.GetMerchandisers());
Merchandisers = new ObservableCollection<Models.Merchandiser>()
{
new Models.Merchandiser { Id=1, Name="Barney Rubble", Phone="021 321 654", Email="barney#rubble.com"},
new Models.Merchandiser { Id=2, Name="Frank Grimes", Phone="022 456 789", Email="grimey#homersfriend.com"},
new Models.Merchandiser { Id=3, Name="Perry Platypus", Phone="023 789 456", Email="perry#agentp.com"},
};
}
Update:
in MerchandiserProfilePageViewModel, get rid of the properties for Name, Phone and EMail
then in MerchandiserProfilePage.xaml change the bindings
<Entry Text="{Binding SelectedMerchandiser.Name}" IsEnabled="False"/>

How to bind content inside another content in Xamarin.UWP?

I'm creating controls in one page that have other controls of their own.
I'm trying to bind the content of a frame inside another bound content, but it crashes if I try to access it the second time.
Also tried to change bind mode to TwoWay with the same result.
Xamarin Forms: 5.0.0.2012
Xamarin.Essentials: 1.6.1
PropertyChanged.Fody: 3.3.2
Main 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" xmlns:test="clr-namespace:Test"
x:Class="Test.MainPage">
<ContentPage.BindingContext>
<test:MainViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Button Text="Some Content View"
Command="{Binding ChangeToContent}"/>
<Button Text="Some other Content View"
Command="{Binding ChangeToOtherContent}"
/>
<Frame Content="{Binding model.MainContent}"/>
</StackLayout>
</ContentPage>
MainViewModel-->
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;
namespace Test
{
public class MainViewModel : INotifyPropertyChanged
{
public MainModel model { get; set; } = new MainModel();
public Command ChangeToContent => new Command(() => {
model.MainContent.Content = new Test1Content();
});
public Command ChangeToOtherContent => new Command(() => {
model.MainContent.Content = new Test2Content();
});
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
Main Model -->
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
using Xamarin.Forms;
namespace Test
{
public class MainModel : INotifyPropertyChanged
{
public Frame SomeContent { get; set; } = new Frame()
{
BackgroundColor = Color.Red,
WidthRequest = 40,
HeightRequest = 40
};
public Frame SomeOtherContent { get; set; } = new Frame()
{
BackgroundColor = Color.Blue,
WidthRequest = 40,
HeightRequest = 40
};
public ContentView MainContent { get; set; } = new ContentView();
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
First Content View -->
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Test.Test1Content">
<ContentView.Content>
<StackLayout>
<Label Text="This is Test 1 Content" />
<Frame Content="{Binding model.SomeContent}"/>
</StackLayout>
</ContentView.Content>
</ContentView>
Second Content
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Test.Test2Content">
<ContentView.Content>
<StackLayout>
<Label Text="This is Test 2 Content" />
<Frame Content="{Binding model.SomeOtherContent}"/>
</StackLayout>
</ContentView.Content>
</ContentView>
Result: https://imgur.com/a/caN9gxX
1st Image is the startup
2nd Image is after pressing top button
3rd Image is after pressing the button under
4th Image is of the error's stack trace after pressing top button again
I may have found a solution. The hint was in https://github.com/xamarin/Xamarin.Forms/issues/2713.
If I modify the Command ChangeToOtherContent and ChangeToContent in my Viewmodel like this:
public Command ChangeToContent => new Command(() => {
model.MainContent.Content = null;
model.MainContent.Content = new Test1Content() { BindingContext = this };
});
public Command ChangeToOtherContent => new Command(() => {
model.MainContent.Content = null;
model.MainContent.Content = new Test2Content() { BindingContext = this };
});
the app doesn't crash.
The null content is important if I trigger the command successively. It can probably be replaced by a bool, testing if the user has triggered the command more than once, but that would imply a lot more tests.
I don't understand why the bindingcontext needs to be added, as it is correct the first time it gets rendered. Maybe someone can add to this.

Xamarin remove item from list ObservableCollection and listview form

I have a simple app on Xamarin (a to-do list) which purpose is to dynamically create and remove items from a list. I am using ObservableCollection for the list. I spent a ton of time researching about this but I could not get it working.
Right now my app can add items to the list and display it in the main form. Now I want it to delete the corresponding items from the list with a click of a button.
Here is my code:
MainPage.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"
xmlns:local="clr-namespace:App3"
x:Class="App3.MainPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add" Clicked="addnewitem"/>
</ContentPage.ToolbarItems>
<ContentPage.BindingContext>
<local:viewmod/>
</ContentPage.BindingContext>
<StackLayout>
<Editor x:Name="txtboxNAME"></Editor>
<ListView ItemsSource="{Binding Tasks}" HasUnevenRows="True" x:Name="itemListView">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame>
<StackLayout>
<Editor Text="{Binding Taskname}"/>
<Switch/>
<Button Text="Delete" CommandParameter="{Binding ItemName}" Clicked="DeleteClicked">
</Button>
</StackLayout>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
MainPage.xaml.cs (The code behind the MainPage form)
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace App3
{
public partial class MainPage : ContentPage
{
static int itemid = 0;
public MainPage()
{
InitializeComponent();
BindingContext = new viewmod();
}
private void addnewitem(object sender, EventArgs e)
{
var vm = BindingContext as viewmod;
string itemnameval = "item_" + itemid.ToString();
vm.AddItems(this.txtboxNAME.Text, itemnameval);
itemid++;
}
private void DeleteClicked(object sender, EventArgs e) // Item should be deleted from the list
{
// This does not work
var itemsender = (Xamarin.Forms.Button)sender;
var item = itemsender?.BindingContext as Task;
var vm = BindingContext as viewmod;
vm?.RemoveCommand.Execute(item);
//vm.Tasks.Remove(item); // conversion error
// This does not work either. "allItems" is not defined.
TaskClass listitem = (from itm in allItems
where itm.ItemName == item.CommandParameter.ToString()
select itm).FirstOrDefault<TaskClass>();
allItems.Remove(listitem);
}
}
}
TaskClass.cs
namespace App3
{
class TaskClass
{
public string Taskname { get; set; }
public string ItemName { get; set; }
}
}
viewmod.cs
using System.Collections.ObjectModel;
using Xamarin.Forms;
namespace App3
{
class viewmod
{
public ObservableCollection<TaskClass> Tasks { get; set; } = new ObservableCollection<TaskClass>();
public viewmod()
{
}
public void AddItems(string taskn, string taskid)
{
Tasks.Add(new TaskClass { Taskname = $"{taskn}", ItemName=$"{taskid}" });
}
public void DelItem(TaskClass task)
{
Tasks.Remove(task);
}
public Command<TaskClass> RemoveCommand
{
get
{
return new Command<TaskClass>((task) =>
{
Tasks.Remove(task);
});
}
}
}
}
modify your XAML first = the "." syntax passes the entire bound object
<Button Text="Delete" CommandParameter="{Binding .}" Clicked="DeleteClicked" />
then in your code behind
private void DeleteClicked(object sender, EventArgs e)
{
var itemsender = (Xamarin.Forms.Button)sender;
var item = (TaskClass)itemsender?.CommandParameter;
// it would be much cleaner to keep a ref to your VM in your page
// rather than continually casting it from BindingContext
var vm = BindingContext as viewmod;
vm.Tasks.Remove(item);
}

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