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;
}
Related
I have a ListView which is bound to some data I have in the viewmodel. In the ListView, each row is a check box and the name of a symptom (e.g. coughing). At the end of the ListView, in the footer, I have a button to submit all of the checkboxes the user has checked.
<ListView x:Name="SymptomsListView" ItemsSource="{Binding SymptomList}" HasUnevenRows="True" SelectionMode="None" Footer="">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="12,0,0,0">
<CheckBox IsChecked="{Binding IsChecked}" Color="ForestGreen" WidthRequest="50" HeightRequest="50" />
<Label Text="{Binding SymptomName}" VerticalOptions="Center" Margin="0,20" FontSize="24" TextColor="Black" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.FooterTemplate>
<DataTemplate>
<ContentView>
<StackLayout>
<Button Text="Submit" TextColor="{StaticResource AppTextColor}" FontAttributes="Bold" FontSize="20" WidthRequest="220" HeightRequest="50" Margin="0,15" HorizontalOptions="Center" CornerRadius="10" BackgroundColor="{StaticResource ButtonColor}" Clicked="SubmitClick"/>
</StackLayout>
</ContentView>
</DataTemplate>
</ListView.FooterTemplate>
</ListView>
In the code behind, I want the button press to submit the checked check boxes as a new object per checked item. Format is explained in the commented code -
protected void SubmitClick(object sender, EventArgs e)
{
// Result output per symptom for the user e.g.
// If Breathlessness is checked with severity 4, Cough is checked with severity 8 & PTSD is checked with severity 2
// new AssessmentModel(UserID, Breathlessness, True, 4);
// new AssessmentModel(UserID, Cough, True, 8);
// new AssessmentModel(UserID, PTSD, True, 2);
// CODE HERE
this.Navigation.PopAsync();
}
How would I perform this? From what I can see there is no way to loop over ListView items to find which have been checked. Any help appreciated
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;
}
Using Xamarin.Forms. I have a ListView containing multiple ViewCells and in each one is a Picker and an Editor. Tapping the Editor fires Editor_Focused, but for some reason also fires Picker_Focused and Picker_Unfocused. I use the Picker_Unfocused event handler to add some data to a SQLite database and then refresh the ListView, so I can't have it firing every time the Editor is tapped. Following along with breakpoints, my refresher method is called twice, because Picker_Unfocused is also called twice for unknown reaons. Also worth noting is that Editor_Completed won't fire no matter what I do.
Things I have tried:
Adding a TapGestureRecognizer to the Editor which would set a property, which would then stop Picker_Unfocused from continuing its execution, but the TapGestureRecognizer never fires when the Editor is tapped.
Assigning a value to a property when Editor_Focused is fired that would do the same as above. Editor_Focused does fire first, but then leaves that property in the "don't fire Picker_Unfocused" state even when the Picker actually needs to be used. Countering that by setting the property back to "do fire" state in Picker_Focused doesn't work, as the order goes Editor_Focused -> Picker_Focused -> Picker_Unfocused -> Refresh list method.
Update: Forgot to include any code.
ListView defined in XAML.
<ListView x:Name="ListView"
HasUnevenRows="True"
SelectionMode="None">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Margin="0,5,0,0">
<Label Text="{Binding Prop0}"
TextColor="DodgerBlue"
VerticalOptions="Center"/>
<Label Text="{Binding Prop1}"
TextColor="Black"
HorizontalOptions="StartAndExpand"
VerticalOptions="Center"/>
<Label Text="Task Time:" TextColor="Black" HorizontalOptions="End"
VerticalOptions="Center"/>
<Picker x:Name="Picker" WidthRequest="80"
Title="Enter time"
FontSize="15"
Focused="Picker_Focused"
Unfocused="Picker_Unfocused"
SelectedItem="{Binding Prop2}">
<Picker.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>0.25</x:String>
<x:String>0.50</x:String>
<x:String>0.75</x:String>
<x:String>1.00</x:String>
</x:Array>
</Picker.ItemsSource>
</Picker>
</StackLayout>
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
IsVisible="{Binding Prop3}">
<Label Text="Comments:" TextColor="Black" VerticalOptions="Center"/>
<Editor x:Name="Editor" Text="{Binding Prop4}" TextColor="Black"
VerticalOptions="Center" HorizontalOptions="StartAndExpand" Focused="Editor_Focused"/>
</StackLayout>
</StackLayout>
<ViewCell.ContextActions>
<MenuItem Text="Delete"
x:Name="DeleteButton"
Clicked="DeleteButton_Clicked"
IsDestructive="True"
CommandParameter="{Binding .}"/>
</ViewCell.ContextActions>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
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);
}
How do I make use of the Tapped action in the ViewCell to navigate to other page?
Xmal codes
<TableView Intent="Settings" HasUnevenRows="true" VerticalOptions="StartAndExpand" BackgroundColor="White" >
<TableRoot>
<TableSection>
<ViewCell Height="100" Tapped="OnProfileClicked">
<ViewCell.View>
<StackLayout Orientation="Horizontal" Padding="5,2,5,2" BackgroundColor="White" >
<Image x:Name="ImgProfile" HeightRequest="100"/>
<Label x:Name="btnName" VerticalOptions="Center" TextColor="Black" FontSize="20"/>
<Label Text="> " FontSize="15" HorizontalOptions="EndAndExpand" VerticalOptions="Center"/>
</StackLayout>
</ViewCell.View>
</ViewCell>
</TableSection>
</TableRoot>
</TableView>
CS File
public void onProfileTapped()
{
Navigation.PushAsync(new Clubs());
}
so there are a couple things that are wrong with your code.
1.) You wrote Tapped=OnProfileClicked but the method you actually made is called onProfileTapped(), this is a mismatch
2.) The parameters for your item tapped event are wrong, most Xamarin events contain a sender and eventArgs.
Here's how you can fix your code to make it work:
void OnProfileClicked (object sender, System.EventArgs e) { //your code}
Also, tip, when you push a page using Navigation. You might want mark the method as async and await the action to make sure it's a smooth transition.