I have created a listview that is being populated from an SQLite DB. The XML looks like this:
<ListView x:Name="CalculationListview" ItemsSource="{Binding Calculation}" HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Qty}"></Label>
<Label Text="{Binding Note}"></Label>
<Button Text="Delete" Clicked="Handle_Clicked"></Button>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have created a button as you can see, from which I want to delete the item from the database if it's clicked.
I have already made a method for deleting from the database, that takes in a given object.
public Task<int> DeleteCalculationAsync(Calculation calculation)
{
return database.DeleteAsync(calculation);
}
Unfortunately, I don't know how to fetch the object from my bindingcontext so that I can delete the item. I obviously have the clicked eventhandler in place already:
void Handle_Clicked(object sender, System.EventArgs e)
{
App.Database.DeleteCalculationAsync(SOMETHING HERE);
}
Context Actions
I recommend moving the delete functionality to Context Actions.
The Context Actions will appear on iOS when the user swipes right-to-left on the ViewCell and on Android when the user long-presses the ViewCell.
Example Screenshot
This screenshot is from the Xamarin.Forms docs and does not reflect the code below.
Code
<ListView x:Name="CalculationListview" ItemsSource="{Binding Calculation}" HasUnevenRows="true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Text="Delete" IsDestructive="True" Clicked="Handle_Delete"/>
</ViewCell.ContextActions>
<StackLayout>
<Label Text="{Binding Qty}"></Label>
<Label Text="{Binding Note}"></Label>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
async void Handle_Delete(object sender, System.EventArgs e)
{
var viewCellSelected = sender as MenuItem;
var calculationToDelete = viewCellSelected?.BindingContext as Calculation;
await App.Database.DeleteCalculationAsync(calculationToDelete);
}
Related
I am learning Xamarin, I would like to get the value of the carousel item selected. I cannot add ItemSelected as in a listview.
Here my Xaml code :
<CarouselView x:Name="NewsList" >
<CarouselView.ItemTemplate >
<DataTemplate>
<StackLayout>
<Frame HasShadow="True"
BorderColor="DarkGray"
CornerRadius="5"
Margin="20"
HeightRequest="300"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<StackLayout>
<Label Text="{Binding NewsName}"
FontAttributes="Bold"
FontSize="Large"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Image Source="{Binding NewsImageUrl}"
Aspect="Fill"
HeightRequest="150"
WidthRequest="150"
HorizontalOptions="Center" />
<Label Text="{Binding ProviderAndDate}"
HorizontalOptions="Center" />
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
Here is the function I would like to use once my item is selected: Get the value of NewsName and ProviderAndDate
private void OnFrameTapped(object sender, EventArgs e)
{
Console.WriteLine("SelectedNewsName" + "SelectedNewsProviderAndDate");
}
Thanks for your help
CarouselView is sort of a different control when it comes to visualization and events than a ListView so you will have to come up with sort of a different solution too
The easiest way to do something similar to a selected item event here would need customization from your side to add the event in.
A good workaround would be just using the CurrentItem property or passing a CommandParameter on the Tap of a Frame!
<StackLayout>
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding CarouselItemTapped,Source={x:Reference currentPage}}" CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<Frame ...... />
And then give your current contentpage a x:Name
<ContentPage ..... X:Name="currentPage"
Now in your xaml.cs
Public ICommand CarouselItemTapped{ get; set; }
In the Constructor:
CarouselItemTapped= new Xamarin.Forms.Command((selectItem)=>{//Perform action here});
Feel free to get back if you have questions
More about Commands: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/commanding
More about CarouselView: https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/carouselview/
Late but it might help someone. The one who is using BindingContext to bind the data, they can get tapped model as shown below.
private void OnFrameTapped(object sender, EventArgs e)
{
var frame = sender as Frame;
var x = frame.BindingContext as YOURMODEL;
}
Problem:
After following a few examples, one, two, three, I am not able to get my ContextActions to connect to my Code Behind.
This is from the examples. MenuItem_Clicked is not connecting the XAML to the code behind
<ViewCell.ContextActions>
<MenuItem Clicked="MenuItem_Clicked" Text="TEST" Command="{Binding .}"/>
</ViewCell.ContextActions>
Setup:
I am just working with a basic example i found online. it is not a MVVM. I have the ListItems_Refresh action setup and working.
Goal of the Code:
When the users clicks a row, I want to open the default browser and go to the URL from the row.
I would love to know how i can troubleshoot this issue or if i have glaring typo. Thanks in advance
Code:
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:HelloWorld"
x:Class="HelloWorld.MainPage">
<StackLayout Margin="20">
<Label Text="60 Second Sports" FontAttributes="Bold" HorizontalOptions="Center"/>
<ListView x:Name="rssList" IsPullToRefreshEnabled="True" Refreshing="ListItems_Refreshing">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.ContextActions>
<MenuItem Clicked="MenuItem_Clicked" Text="TEST" Command="{Binding .}"/>
</ViewCell.ContextActions>
<StackLayout>
<Label Text="{Binding Title}" Font="8"/>
<!--<Label Text="{Binding Description}" Font="6"/>-->
<Label Text="{Binding PublishedDate}" Font="5"/>
<Label Text="{Binding Link}" Font="5"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
Code Behind
private void MenuItem_Clicked(object sender, EventArgs e)
{
Console.WriteLine("button was clicked");
System.Diagnostics.Process.Start("http://google.com");
}
protected void ListItems_Refreshing(object sender, EventArgs e)
{
Console.WriteLine("refresh triggered");
//doRefresh();
//my method for repopulating the list ImageListView.EndRefresh();
//this is a very important step. It will refresh forever without triggering it }
}
If you want to open a browser when you click on a ListView item, you can just listen to the ItemTapped event.
ItemTapped fires when an item is tapped.
So, in your ListView
<ListView x:Name="rssList" IsPullToRefreshEnabled="True"
ItemTapped="listItemTapped"
Refreshing="ListItems_Refreshing">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text="{Binding Title}" Font="8"/>
<!--<Label Text="{Binding Description}" Font="6"/>-->
<Label Text="{Binding PublishedDate}" Font="5"/>
<Label Text="{Binding Link}" Font="5"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And, the listener method.
public void listItemTapped(object sender, ItemTappedEventArgs e)
{
Console.WriteLine("button was clicked");
var item = (YourModel)e.Item;
}
I have a list view in my XAML code for displaying items in a list, I would like to "select" on when I double click on it.
<ListView x:Name="sounds">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" DoubleTapped="select_cue({Binding})">
<TextBlock .../>
<Slider .../>
...
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
What I would like is the function in my C# code to be called when the StackPanel is "DoubleTapped".
public void select_cue(SoundCue cue) {
//find cue in list of cues
//make current cue point to passed in cue if it is in the list
}
However, when I try and compile this I get "Error: CS1026 ) expected". I have tried to search around for this functionality which I am sure exists (because similar styles of application APIs like AngularJS do have this functionality).
You need to change your mode of accessing items in a little different way.
<ListView x:Name="sounds">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" DoubleTapped="StackPanel_DoubleTapped">
<TextBlock .../>
<Slider .../>
...
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And your StackPanel_DoubleTapped Will be
private void StackPanel_DoubleTapped(object sender, DoubleTappedRoutedEventArgs e)
{
//Since you are databinding your sounds, sounds.SelectedItem will be your selected cue.
}
I am using Xamarin.Forms, and I'm looking for a way to have a databound ListView with custom cells, and in those custom cells, there is a Delete button that is bound to a Command in my ViewModel.
Here is my code...
<ListView ItemsSource="{Binding SelectedServiceTypes}" IsVisible="{Binding ShowSelectedServiceTypes}" HeightRequest="110" RowHeight="30">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Horizontal" HeightRequest="30">
<Label Text="{Binding ServiceCode}" HeightRequest="30" />
<Label Text="-" HeightRequest="30" />
<Label Text="{Binding ServiceDescription}" HeightRequest="30" />
<Button
Text="Delete"
HeightRequest="30"
HorizontalOptions="End"
VerticalOptions="Start"
Command="{Binding DeleteServiceTypeCommand}"
CommandParameter="{Binding ID}" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The ListView is bound to an ObservableCollection. I want the delete button to use a Command and pass a CommandParameter to my View Model.
private Command _deleteServiceTypeCommand;
public Command DeleteServiceTypeCommand
{
get
{
if (_deleteServiceTypeCommand == null)
_deleteServiceTypeCommand = new Command<string> ((serviceTypeID) => RemoveServiceType (serviceTypeID) );
return _deleteServiceTypeCommand;
}
}
I wasn't sure if this is possible in Xamarin.Forms. It's almost like the cell needs to have two BindingContext, one being the element in the collection(to get the ID value) and the other being the View Model(to have the Command work).
Any ideas?
So after more research, I was able to find the nuget package Xamarin.Forms.Behaviors which adds something similar to RelativeSource binding.
https://github.com/corradocavalli/Xamarin.Forms.Behaviors
It's implementation example can be found here.
http://codeworks.it/blog/?p=216
I'm working with Xamarin Forms and MVVMLight.
So I'm displaing a List of "Patients" with a ListView. Each Element of the ListView has a Delete-Button. When clicked the Patient is deleted from the List and the View is notified with RaisePropertyChanged().
The Problem now is that when I add multiple Patients and then want to delete one. Always the last one is removed in the View. I debugged the App and saw that the right one is delted from my List. But when the View updates its data, always the last Entry is removed.
<ListView ItemsSource="{Binding Patients}" HasUnevenRows="true" x:Name="Patientlist">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Horizontal" VerticalOptions="FillAndExpand">
<StackLayout HorizontalOptions="FillAndExpand">
<Label Text="Patient" Style="{DynamicResource TitleStyle}"/>
<Label Text="Benötigte Proben"/>
<Label Text="Untersuchungen"/>
<Button Text="Bearbeiten" />
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand">
<Label Text="{Binding PatientID}"/>
<Label Text="Test"/>
<Label Text="Test"/>
<Button Text="Löschen" Command="{Binding DelCMD}"/>
</StackLayout>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
So this is my ListView. The Button "Löschen" ist the delete-Button. It executes the following Command:
private RelayCommand delCMD;
public RelayCommand DelCMD
{
get
{
return delCMD ?? (delCMD = new RelayCommand (()=>Messenger.Default.Send<PatientM> (this, "delPat")));
}
}
This code is in my PatientModel-Class. And sends a Message to the VM where the Element is removed.
public void delPatient(PatientM Patient)
{
Patients.Remove (Patient);
RaisePropertyChanged ("Patientlist");
}
This code is then executed in the VM. An well like I said the right Patient is removed from the List (Patients.Remove). But after RaisePropertyChanged is called the wrong is Element is delted in the View. Always the last one even tough I deleted another on in the List.