Can't select same item twice on CollectionView - xamarin.forms

I use a CollectionView control to display a list of files, if users click an item a popup appears displaying information about the file and a button to download it, the problem is that I use the SelectionChanged method of the CollectionView to run this action, but if users close the popup and click again on the same item nothing happens. Back when we use ListView control, the ItemTapped event runs every time the users click the same item, but i need to changed to CollectionView because later we'll change the file item from a single row to multiple columns (2 or 3).
It is possible to make the users click on the same item multiple times with CollectionView control ?
P.D: also try to set the SelectedItem to null but the app crashes if the users select again the same item.

It works for me when i set SelectedItem to null.What else did you do when you set selectitem?
below is my simple sample,i use DisplayAlert instead of popup.
the xaml :
<CollectionView x:Name="collection" SelectionChanged="CollectionView_SelectionChanged" SelectionMode="Single" >
<CollectionView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>Baboon</x:String>
<x:String>Capuchin Monkey</x:String>
<x:String>Blue Monkey</x:String>
<x:String>Squirrel Monkey</x:String>
<x:String>Golden Lion Tamarin</x:String>
<x:String>Howler Monkey</x:String>
<x:String>Japanese Macaque</x:String>
</x:Array>
</CollectionView.ItemsSource>
</CollectionView>
in page xaml.cs:
private async void CollectionView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (collection.SelectedItem != null)
{
await DisplayAlert("Question?", "Would you like to play a game", "Yes", "No");
collection.SelectedItem = null;
}
}
the effect is like below:

Related

Xamarin forms iOS CollectionView steals focus after ItemsSource property is changed

I have a page with a collection view and a search bar that filters its contents.
I want the filtering to happen as the user types in the search bar, so I bind the TextChanged event of the SearchBar to a command in the view model, like so
var eventToCommandBehavior = new EventToCommandBehavior()
{
EventName = nameof(searchBar.TextChanged),
};
eventToCommandBehavior.SetBinding(EventToCommandBehavior.CommandProperty, nameof(MyViewModel.StartOrResetSearchTimerCommand));
searchBar.Behaviors.Add(eventToCommandBehavior);
In the view model:
public ICommand StartOrResetSearchTimerCommand => new Command(() =>
{
StartOrResetSearchTimer();
});
private void StartOrResetSearchTimer()
{
if (!timerStarted)
{
searchTimer = new Timer(_ => PerformSearch(), null, searchTimeout, searchTimeout);
timerStarted = true;
}
else
ResetTimer();
}
private void PerformSearch()
{
//my code
OnPropertyChanged(collectionViewItemsSourceBinding);
}
The StartOrResetSearchTimerCommand filters the ItemsSource binding, and calls OnPropertyChanged(itemsSourceBinding) to update the UI.
On Android and UWP everything works as expected. However on iOS, when OnPropertyChanged is called, the focus moves out of the search bar, resulting to the soft keyboard being closed after each keyboard input.
Has anyone else encountered this? Any suggestions?
I have already tried not using this approach, and only filter the ItemsSource when the search button is pressed, which works, when there is something to search for (ie, there is some input in the search bar)
When the search bar text is empty (ie after Backspace) then the search button is greyed out.
Update
For now, I am using this workaround:
Perfom the search only when the search button is pressed, and on TextChanged, check if the text is empty and reset the ItemsSourceworka
TextChanged is called anytime the text in the query box is changed. You can use this event to update your ItemsSource when the Text of the searchbar changes. You can refer to this part of the official example. First, given your ItemsSource, when you enter text in the searchbar, call the OnTextChanged event to update your ItemsSource, so that the real-time search keyboard will not lose focus.

Xamarin Forms - Issue with Swipe to Delete on iOS

So I implemented swipe to delete functionality for iOS and long tap to delete for Android, everything works fine except - on iOS after swiping a cell and clicking delete button I am displaying Alert to confirm if user wants to delete item# XYZ, when alerts pops up another cell gets swiped.
Any suggestions how to fix it?
XAML:
<ViewCell.ContextActions>
MenuItem CommandParameter="{Binding .}" Text="Delete" IsDestructive="True" Command="{Binding Path=BindingContext.DeleteCommand, Source={x:Reference Name=ListPage}}"
</ViewCell.ContextActions>
ViewModel (when delete command is called):
string Msg = string.Format("Delete item {0}?", selectedItem.ItemNumber);
var answer = await App.Current.MainPage.DisplayAlert(App.ResourceContainer.GetString("Confirmation_Message"),
Msg,
App.ResourceContainer.GetString("Yes"),
App.ResourceContainer.GetString("No"));

MaterialDesignXaml dialog from Caliburn.Micro View Model

I'm having a problem with showing Dialogs from a View Model. The problem is that the "underlying content is not dimmed and disabled" as the documentation says it should be. If I click on the underlying view the button in the dialog wired to the closed command is sometimes disabled and the user is not able to click it.
I defined the DialogHost in my MainView like this (also tried it in the ShellView):
<materialDesign:DialogHost
HorizontalAlignment="Center"
VerticalAlignment="Center"
CloseOnClickAway="True" />
From my MainViewModel I show the dialog like this:
Dim errView As New ErrorView
Dim res = Await DialogHost.Show(errView)
I wired up the close command on a button in the ErrorView dialog like this:
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
You problem is with the definition of DialogHost; you have it as an empty element.
The DialogHost is a ContentControl. Everything inside is what will become dimmed. So you define it at the root of your main Window/Page XAML, a bit more like:
<materialDesign:DialogHost CloseOnClickAway="True">
<StackPanel>
<TextBlock>Hello World</TextBlock>
<TextBlock>This is the main content of my application</TextBlock>
</StackPanel>
</materialDesign:DialogHost>

How to configure ExpressionTextBox bindings / OwnerActivity when used in a dialog?

Our group is working on a Custom Activity Designer around our Email activity. It's a pretty straight forward designer, allow the user to enter settings / creds, but instead of cluttering the activity designer with all the settable options, we thought about putting some settings in a dialog window. (Which opens when you click the button beside the server address box).
Some of our email activity properties are InArguments so we are trying to make use of the ExpressionTextBox to display these values without much luck. The main problem is we aren't sure how to properly set up the binding and the OwnerActivity on the ExpressionTextBox. In the Activity Designer's xaml this is simply done by setting Expression=ModelItem.Property using a converter for the InArgument and setting the OwnerActivity=ModelItem, like this:
<view:ExpressionTextBox HintText="Enter a VB Expression" Expression="{Binding ModelItem.ServerAddress, ConverterParameter=In, Converter={StaticResource ArgumentToExpressionConverter}, Mode=TwoWay}" ExpressionType="{x:Type system:String}" OwnerActivity="{Binding ModelItem}" Margin="2" MaxLines="1" />
If anyone has any ideas on how we could accomplish this in a dialog, please advise.
Well, this is more a WPF\MVVM question than WF4, really.
When developing custom activities designers you just have to keep one thing in mind: any change made on designer\dialog should be reflected on ModelItem. Either through XAML binding expressions or through code on ModelItem.Properties property.
Now, when and how you do it, there are several answers to that but that's really an implementation detail and depends on how you want to do it.
Lets assume you're showing the dialog on button-beside-the-server-address-box click. And lets also assume you've access to dialog textboxes through their name. At that point, you've access to ModelItem so just set its properties as needed:
private void ButtonNextToServerAddressBox_OnClick(object sender, RoutedEventArgs e)
{
var dialog = new ServerAddressEditor();
var result = dialog.ShowDialog();
if (result ?? false)
{
ModelItem.Properties["Server"].SetValue(new InArgument<string>(dialog.ServerTextBox.Text));
ModelItem.Properties["Port"].SetValue(new InArgument<string>(dialog.PortTextBox.Text));
// ... set all other properties
}
}
Now, if you are using any other pattern, or you want pure MVVM, it can be a little more tricky because of how ModelItem works. But this is a totally fine approach.
I resolved this by creating a property in the dialog's ViewModel to hold the Activity Designer's ModelItem.
public ModelItem OwnerActivity {
get { return _OwnerActivity; }
set { _OwnerActivity = value; }
}
vm.OwnerActivity = this.DataContext.ModelItem;
I then set the Xaml for the Expression Text Box in my dialog to binding to this:
<view:ExpressionTextBox HintText="Enter a VB Expression" Expression="
{Binding Path=OwnerActivity.ServerAddress, ConverterParameter=In, Converter=
{StaticResource ArgumentToExpressionConverter}, Mode=TwoWay}" ExpressionType="
{x:Type system:String}" OwnerActivity="{Binding OwnerActivity}" Margin="2"
MaxLines="1" />
Because I'm now binding directly to the ModelItem from the Activity Designer, any change made to the ModelItem property from the dialog is ALWAYS committed, even if you choose to Cancel from the dialog. To wire up the Ok/Cancel buttons so they work accordingly, I did the following in the dialog:
// declare a ModelEditingScope to make changes transactional
private ModelEditingScope _editScope;
// add this to the constructor of the dialog to begin transactional edits on the ModelItem
_editScope = editorViewModel.OwnerActivity.BeginEdit();
// ok & cancel button click event to commit or revert the changes.
private void OK_Click(object sender, RoutedEventArgs e)
{
_editScope.Complete();
this.DialogResult = DialogResult.OK;
this.Close();
}
private void Cancel_Click(object sender, RoutedEventArgs e)
{
_editScope.Revert();
this.DialogResult = DialogResult.Cancel;
this.Close()
}

Where should I put my code in ActionBar.TabListener

I have just started with an ActionBar.TabListener with 3 tabs.
I selected new "Tabbed activity" in Android Studio.
My activity is called test...not the best name but I'm just trying to learn:)
I have a listView in fragment_test.xml that I want to fill with data after a raw sql search.
If I put this code in onCreateView then everytime I click on a tab it will re-write that tab with the same info in the listView.
What I want is to have diffrent information in those tabs.... then I need to know which tab that is clicked. That I did with mViewPager.getCurrentItem() ....Is this right? How can i get the name of the tab instead?
I have also found onTabSelected...should I put my code here? In this case I think I know which tab that is selected but is it really wise to put the code here?
If I do this then listView1 becomes null...why?:
public void onTabSelected(ActionBar.Tab tab, FragmentTransaction fragmentTransaction) {
listView1 = (ListView)findViewById(R.id.listView2);
listAdapter2 = new ArrayAdapter<String>(context, R.layout.simplerow, testArray);
listAdapter2.notifyDataSetChanged();
listView1.setAdapter(listAdapter2);
<ListView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/listView2"
android:layout_centerHorizontal="true" />
If I understand it correctly, you want to load Fragment's ListView according to Tab's selected position.
If that's the case, you should not modify Fragment's ListView in Activity. Instead, pass Tab's selected position to Fragment as an argument from Activity and load ListView in Fragment according to that position.

Resources