how to clear collectionview selection in xamarin - c#

On Page#1, i have a collectionview with text/string items list. If you tap a a item, it will get the current tapped text/string and send to Page#2. sound simple
issue I am having: if you tap on item#1, then it will send item#1 to page2, this part working fine. But on page#2, if you hit back button, and tap on item#1 again.. than nothing happens, it doesnt go to page#2
Fix: i think i need to somehow clear tap selection, and than send the item to page#2. but im not sure how to do this
On Page#1, i have a simple collectionview. Collection view contains text/string list
<CollectionView ItemsSource="{Binding MyListItem}"
SelectionMode="Single"
SelectionChanged="CollectionView_SelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<ContentView>
<!-- Body -->
<Grid Padding="0">
<Frame CornerRadius="3" BorderColor="#f2f4f5" HasShadow="True">
<StackLayout Orientation="Horizontal">
<Image Source="icon_about"
WidthRequest="25" />
<StackLayout VerticalOptions="Center">
<Label VerticalOptions="Center"
FontSize="16"
Text="{Binding .}" />
</StackLayout>
</StackLayout>
</Frame>
back end code to handle selection is:
private async void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var previous = e.PreviousSelection.FirstOrDefault();
var current = e.CurrentSelection.FirstOrDefault();
var route = $"{ nameof(Page2) }?URLCardType={current}";
await Shell.Current.GoToAsync(route);
//clear selection
((CollectionView)sender).SelectedItem = null;
}
Update ((CollectionView)sender).SelectedItem = null; fixed the issue of clearing selected item but CollectionView_SelectionChanged method is get run twice on single tap. why? this is all the code i have

#jason thanks, this worked for me. i just had to check if selection item is null than do nothing
private async void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var MyCollectionView = sender as CollectionView;
if (MyCollectionView.SelectedItem == null)
return;
var previous = e.PreviousSelection.FirstOrDefault();
var current = e.CurrentSelection.FirstOrDefault();
var route = $"{ nameof(Page2) }?URLCardType={current}";
await Shell.Current.GoToAsync(route);
//clear selection
MyCollectionView.SelectedItem = null;
}

Here is a simple solution that worked for me.
Setting to null did not do the trick, it was causing all kinds of
weird stuff.
private void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var itemselected = e.CurrentSelection[0] as ProductsItem;
if (itemselected != null)
Shell.Current.GoToAsync(nameof(SelectedProductPage));
//Setting the selected item to an emptyviewproperty after navigation
CollectionList.SelectedItem = SelectableItemsView.EmptyViewProperty;
}

Related

Xamarin Forms FindByName always returns null

I have a ContentPage that is bound to a viewmodel. Still, at one point, I need to access a Picker inside a StackLayout which in turn is in a Syncfusion ListViewItem. The XAML is pretty straightforward:
<?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" xmlns:sf="clr-namespace:Syncfusion.ListView.XForms;assembly=Syncfusion.SfListView.XForms"
mc:Ignorable="d"
x:Class="PerformanceTM.Views.NewCircuitView">
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<sf:SfListView x:Name="ExerciseList" ItemsSource="{Binding Exercises}" DragStartMode="OnHold">
<sf:SfListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Picker Title="Kategorie" x:Name="CategoryPicker" ItemsSource="{Binding Source={x:Reference ExerciseList}, Path=BindingContext.ExerciseCategories}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding Category}" SelectedIndexChanged="CategoryChanged"/>
<Picker Title="Übung" x:Name="ExerciseNamePicker" ItemDisplayBinding="{Binding Name}" SelectedIndexChanged="ExerciseSelected"/>
<Button Text="..." Clicked="ConfigureSetsClicked"/>
<Button Text="(-)" />
</StackLayout>
</ViewCell>
</DataTemplate>
</sf:SfListView.ItemTemplate>
</sf:SfListView>
<StackLayout Orientation="Horizontal">
<Button Text="(+) Übung" Command="{Binding AddExerciseCommand}"/>
<Button Text="Ok" Command="{Binding ApplyChangesCommand}"/>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
As you can see, both Pickers in the ViewCell have x:Name assigned to them. When I select a value in the ExerciseCategoryPicker, I load and assign new values to to ExerciseNamePicker in Code behind, like so:
private async void CategoryChanged(object sender, EventArgs e)
{
var picker = sender as Picker;
var stackLayout = picker.Parent as StackLayout;
ListViewItem listViewItem = stackLayout.Parent as ListViewItem;
var ex = picker.BindingContext as Exercise;
if (ex is null)
return;
ex.Category = picker.SelectedItem as ExerciseCategory;
var apiService = new ApiServices();
var exsForCategory = await apiService.GetExercisesForCategory(ex.Category.Name);
Picker exnp = stackLayout.FindByName<Picker>("ExerciseNamePicker");
if (exnp is null)
exnp = stackLayout.Children.OfType<Picker>().Where(x => x.Title == "Übung").FirstOrDefault();
exnp.ItemsSource = exsForCategory;
if (exsForCategory.Count > 0)
exnp.SelectedItem = exsForCategory.FirstOrDefault();
var bc = this.BindingContext as NewCircuitViewModel;
bc.ExercisePairing.Descriptor = bc.ExercisePairing.UpdateDescriptor();
}
private void ExerciseSelected(object sender, EventArgs e)
{
try
{
var picker = (sender as Picker);
var stackLayout = picker.Parent as StackLayout;
var vc = picker.Parent.Parent as Syncfusion.ListView.XForms.ListViewItem;
var ex = vc.BindingContext as Exercise;
var se = picker.ItemsSource[picker.SelectedIndex] as Exercise;
var exnp = stackLayout.FindByName("CategoryPicker") as Picker;
if (exnp is null)
exnp = stackLayout.Children.OfType<Picker>().Where(x => x.Title == "Kategorie").FirstOrDefault();
var ec = exnp.SelectedItem as ExerciseCategory;
ex.Category = ec;
ex.Name = se.Name;
ex.Id = se.Id;
ex.Description = se.Description;
ex.VideoUrl = se.VideoUrl;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Now what happens is that FindByName() returns null in each situation. Oddly enough, when I debug and inspect the Children of StackLayout just before calling FindByName, it does contain children with the appropriate IDs (i.e., the x:Name). When I access them via get, I get the GUID (this somehow confuses me, as I thought there should only be a GUID in the first place, but well).
I have found a workaround by just selecting the element by Title, but this is a rather strange behaviour, especially considering that this has worked in the past. Only change I made since then was the integration of the SyncFusion ListView. Could that be an issue? Has anyone experienced this and/or can provide more insight?
PS: I have gone through all the "usual" fixes such as deleting the .v, bin and obj folders...
You can get the children element of SfListView.ItemTemplate using behavior for the parent element of the ItemTemplate. Please refer the following code snippet for getting the named elements inside DataTemplate,
Xaml: Define Behavior for StackLayout
<sf:SfListView x:Name="ExerciseList" ItemsSource="{Binding Exercises}" DragStartMode="OnHold">
<sf:SfListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<StackLayout.Behaviors>
<local:Behavior/>
</StackLayout.Behaviors>
<Picker Title="Kategorie" x:Name="CategoryPicker" ItemsSource="{Binding Source={x:Reference ExerciseList}, Path=BindingContext.ExerciseCategories}" ItemDisplayBinding="{Binding Name}" SelectedItem="{Binding Category}"/>
<Picker Title="Übung" x:Name="ExerciseNamePicker" ItemDisplayBinding="{Binding Name}"/>
<Button Text="..." Clicked="ConfigureSetsClicked"/>
<Button Text="(-)" />
</StackLayout>
</ViewCell>
</DataTemplate>
</sf:SfListView.ItemTemplate>
Behavior: Get element using FindByElement. Trigger SelectedIndexChanged event for Picker.
public class Behavior : Behavior<StackLayout>
{
Picker CategoryPicker;
Picker ExerciseNamePicker;
protected override void OnAttachedTo(StackLayout bindable)
{
CategoryPicker = bindable.FindByName<Picker>("CategoryPicker");
ExerciseNamePicker = bindable.FindByName<Picker>("ExerciseNamePicker");
CategoryPicker.SelectedIndexChanged += CategoryPicker_SelectedIndexChanged;
ExerciseNamePicker.SelectedIndexChanged += ExerciseNamePicker_SelectedIndexChanged;
base.OnAttachedTo(bindable);
}
private void ExerciseNamePicker_SelectedIndexChanged(object sender, EventArgs e)
{
//Your logic here.
}
private void CategoryPicker_SelectedIndexChanged(object sender, EventArgs e)
{
//Your logic here.
}
}
You can also refer our online document regarding the same from the following link,
Document

XAML Scroll intoView wont work in async function?

im using the following code to display some tweets in a ListView.
I'm inserting every tweet at position index = 0 to display the latest tweet at the bottom of the listView (x:name = standardTweetBox).
private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e)
{[...]
if (searchResponse != null && searchResponse.Statuses != null)
{
foreach (Status status in searchResponse.Statuses)
{
Tweet tweet = new Tweet(status.User.ScreenNameResponse, status.User.ProfileImageUrl, status.Text, status.CreatedAt.ToString());
standardTweetBox.Items.Insert(0, tweet);
}
}
Usually the following code should work to focus at the latest tweet at the bottom of the listView
standardTweetBox.ScrollIntoView(standardTweetBox.Items[standardTweetBox.Items.Count - 1]);
I was succesfull to implement this line of code at a different part of the code. Of course using the event TextBox_Change doesnt make any sense, but it proves to code to be working.
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
standardTweetBox.ScrollIntoView(standardTweetBox.Items[standardTweetBox.Items.Count-1]);
}
Is it possible that this line of code just doenst work properly in an async function?
Here is my XAML code if needed:
<ListView Grid.Row="1"
x:Name = "standardTweetBox"
ItemTemplate="{StaticResource TweetBox}"
HorizontalAlignment="Center"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VerticalAlignment="Bottom"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
<!--</ScrollViewer>-->
<TextBox Grid.Row="2" Height="150" Width="380" Text="{Binding Title}" Background="#99FFFFFF" TextChanged="TextBox_TextChanged"/>
Let me know if you need any further information.
Cheers

Xamarin Forms ListView Checkmark

I'm trying to implement a ListView in Xamarin Forms. A list that we can check or choose the item that we want. I want a single item selection at a time.
My xaml file :
ListView x:Name="listview" ItemSelected="OnItemSelected" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout HorizontalOptions="StartAndExpand" Orientation="Horizontal">
<StackLayout Padding="20,0,0,0" VerticalOptions="Center" Orientation="Vertical">
<Label Text="{Binding .}" YAlign="Center" FontSize="Medium" />
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My xaml.cs file :
public void OnItemSelected (object sender, SelectedItemChangedEventArgs e) {
if (e.SelectedItem == null) return;
// add the checkmark in the event because the item was clicked
// be able to check the item here
DisplayAlert("Tapped", e.SelectedItem + " row was tapped", "OK");
((ListView)sender).SelectedItem = null;
}
There is a better way to do it?
I want something like this without alphabet and search menu :
Take a look on this https://github.com/ricardoromo/Listview-Multiselect, I made this sample to simulate miltiselect listview.
You could try using XLabs checkbox or radioButton control, Here is a list of controls examples, you just need to download the package via NuGet Manager.
If you only need to check 1 item, in your tapped event make an action after item is tapped. Here's an example:
async void FriendListView_ItemTapped(object sender, ItemTappedEventArgs e)
{
var el = e.Item as ProfileItem;
SelectedItem = el;
if (e.Item != null)
{
await Navigation.PushAsync(new FriendProfile(el));
}
((ListView)sender).SelectedItem = null; // de-select the row
}
I've tried the Multiselection listview in xamarin forms and I got it working for both iOS and Android.
This took me some time so I wrote a blog about the entire prototype. You can find it here :
http://androidwithashray.blogspot.com/2018/03/multiselect-list-view-using-xamarin.html
The blog gives you full info on creating the Listview with the checkbox and selecting multiple items. Hope this helps!!

How to select an item from a listbox in windows phone?

I've a list of data,
Each row will show a data and will have a button, when i click the data shown i want give some data to the previous page and when i click the button in the same row i want to send that same data to next page.
My Xaml code,
<ListBox x:Name="List" HorizontalAlignment="Left" Height="612" Margin="6,7,0,0" VerticalAlignment="Top" Width="443" SelectionChanged="List_SelectionChanged_1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="420" Height="50">
<TextBlock x:Name="tbName" Width="400" Height="44" FontSize="22" FontWeight="Bold" Text="{Binding Name}" />
<Button x:Name="DetailButton" Height="44" Width="20" Content=">" FontWeight="Bold" Click="DetailButton_Click_1"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and the code for List_SelectionChanged_1 event handler is,
private void List_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
Display selectedItemData = (sender as ListBox).SelectedValue as Display;
NavigationService.Navigate("/Page1.xaml",selectedItemData);
}
and my DetailButton_Click_1 event handler is,
private void DetailButton_Click_1(object sender, RoutedEventArgs e)
{
Display selectedItemData = (sender as ListBox).SelectedValue as Display;
NavigationService.Navigate("/page3.xaml", selectedItemData);
}
Things work fine for *List_SelectionChanged_1*, but i get an exception while executing
Display selectedItemData = (sender as ListBox).SelectedValue as Display;
of the DetailButton_Click_1 , i get an exception a null exception,
An exception of type 'System.NullReferenceException' occurred in ExpenseApp.DLL but was not handled in user code
What should i do make it work?
The underlying problem is that the sender of the button click event is the button, not the ListBox.
Also note that clicking the button on your data template will not necessarily select that item in the list. Try to grab the clicked item's data context and use that instead of .SelectedItem
private void DetailButton_Click_1(object sender, RoutedEventArgs e)
{
var clickedUIElement = sender as Button;
if (null == clickedUIElement) { Return; }
Display selectedItemData = clickedUIElement.DataContext as Display;
if(null != selectedItemData)
{
NavigationService.Navigate("/page3.xaml", selectedItemData);
}
}
Your code, as it stands, will have a null reference since you can't cast a Button as a ListBox.
try verify if the selectvalue is null before execute the code:
private void DetailButton_Click_1(object sender, RoutedEventArgs e)
{
If ((sender as ListBox).SelectedValue != null){
Display selectedItemData = (sender as ListBox).SelectedValue as Display;
NavigationService.Navigate("/page3.xaml", selectedItemData);
}
}

Delete task is not working under Context Menu?

I was developing Windows Phone App using this sample: Local Database Sample
In that sample, Delete Task has been implemented using an icon. I have modified Delete Task by Context Menu. But, it does not works for me.
If I pressed Delete, nothing happens.
I dunno what mistake I have done.
My modified Code:
XAML Code:
<TextBlock
Text="{Binding ItemName}"
FontWeight="Thin" FontSize="28"
Grid.Column="0" Grid.Row="0"
VerticalAlignment="Top">
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu Name="ContextMenu">
<toolkit:MenuItem Name="Delete" Header="Delete" Click="deleteTaskButton_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</TextBlock>
C# Code:
private void deleteTaskButton_Click(object sender, RoutedEventArgs e)
{
// Cast the parameter as a button.
var button = sender as TextBlock;
if (button != null)
{
// Get a handle for the to-do item bound to the button.
ToDoItem toDoForDelete = button.DataContext as ToDoItem;
App.ViewModel.DeleteToDoItem(toDoForDelete);
MessageBox.Show("Deleted Successfully");
}
// Put the focus back to the main page.
this.Focus();
}
Working original Code in that sample:
XAML Code:
<TextBlock
Text="{Binding ItemName}"
FontSize="{StaticResource PhoneFontSizeLarge}"
Grid.Column="1" Grid.ColumnSpan="2"
VerticalAlignment="Top" Margin="-36, 12, 0, 0"/>
<Button
Grid.Column="3"
x:Name="deleteTaskButton"
BorderThickness="0"
Margin="0, -18, 0, 0"
Click="deleteTaskButton_Click">
<Image
Source="/Images/appbar.delete.rest.png"
Height="75"
Width="75"/>
</Button>
C# Code:
private void deleteTaskButton_Click(object sender, RoutedEventArgs e)
{
// Cast the parameter as a button.
var button = sender as Button;
if (button != null)
{
// Get a handle for the to-do item bound to the button.
ToDoItem toDoForDelete = button.DataContext as ToDoItem;
App.ViewModel.DeleteToDoItem(toDoForDelete);
MessageBox.Show("Deleted Successfully");
}
// Put the focus back to the main page.
this.Focus();
}
In your case sender is not a TextBlock, so this line:
var button = sender as TextBlock;
returns null
You can cast it to MenuItem.
using Microsoft.Phone.Controls;
....
private void deleteTaskButton_Click(object sender, RoutedEventArgs e)
{
var item = sender as MenuItem;
if (item!= null)
{
// Get a handle for the to-do item bound to the button.
ToDoItem toDoForDelete = item .DataContext as ToDoItem;
App.ViewModel.DeleteToDoItem(toDoForDelete);
MessageBox.Show("Deleted Successfully");
}
// Put the focus back to the main page.
this.Focus();
}

Categories

Resources