Call ICommand outside item source - xamarin.forms

I have an ICommand in my PageViewModel and want it to be call in my CheckedChanged of RadioButton. However, this RadioButton is inside:
<views:RoundedPage>
<Carousel ItemSource="...">
<DataTemplate DataType="...">
<CollectionView ItemSource="...">
<DataTemplate DataType="...">
<RadioButton CheckedChanged="" />
</DataTemplate>
</CollectionView>
</DataTemplate>
</Carousel>
</views:RoundedPage>
So how am I gonna call this command outside those sources.
Thank you

At first, I don't recommend you to deal with the UI event in your view model. The view model is used to resolve the logic behavior behand the view.
So you can set the CheckedChanged event by the following method:
1.create a void method in the page.cs, such as
private void RadioButton_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
//do something
}
2.binding in the xaml
<RadioButton CheckedChanged="RadioButton_CheckedChanged"/>
If you still want to deal with the event in the viewmodel, you need to use the behavior to covert the event to a command.
There is a simple in the official document and you can check it:
https://learn.microsoft.com/en-us/samples/xamarin/xamarin-forms-samples/behaviors-eventtocommandbehavior/

Related

How to display two text boxes as pop up using DisplayPromptAsync method in xamarin?

When I use -
string result = await DisplayPromptAsync("Question 1", "What's your name?");
It shows only one textbox in the pop-up. But how to display two or more textboxes in the pop-up?
Any help would be greatly appreciated.
As IvanIčin said that you can use Rg.Plugins.Popup to create custom popup.
Firstly, install Rg.Plugins.Popup bu nuget package..., then creating popup page
<pages:PopupPage
x:Class="FormsSample.popup.popup2"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:pages="clr-namespace:Rg.Plugins.Popup.Pages;assembly=Rg.Plugins.Popup">
<pages:PopupPage.Content>
<StackLayout
Padding="20,0"
BackgroundColor="CadetBlue"
HorizontalOptions="FillAndExpand"
VerticalOptions="Center">
<Label Text="Question 1" />
<Label Text="this is one question!" />
<Entry />
<Entry />
<Button
x:Name="btnsub"
Clicked="btnsub_Clicked"
Text="subit" />
</StackLayout>
</pages:PopupPage.Content>
</pages:PopupPage>
public partial class popup2 : PopupPage
{
public popup2()
{
InitializeComponent();
}
private void btnsub_Clicked(object sender, EventArgs e)
{
}
}
To call this Popup Page from contentpage button.click event.
private async void btnPopupButton_Clicked(object sender, EventArgs e)
{
await PopupNavigation.Instance.PushAsync(new popup2());
}
You can see the screenshot:
You can't as it is not intended to. You can create a custom pop-up either by using some pop-up plug-in or by creating your custom code based on the native prompts (similar to what Xamarin.Forms do).
Just for the record having one input field is very generous from Xamarin as the native Android or iOS developers don't have such a prompt with the input field out of the box (though it isn't too hard to create it but still it goes much beyond one line of code).

Equivalent of ItemAppearing in xamarin UWP

I have a ListView bind to list of BitmapImage.
I want to get the Index of current image in focus when I scroll thru this list.
But, I notice that ItemAppearing property is not there in UWP but it is there in Xamarin Forms.
How can I get the index of the current item in view?
Thanks!
<ScrollViewer Grid.Row="0" ZoomMode="{x:Bind ZoomMode, Mode=OneWay}" HorizontalScrollMode="Enabled" HorizontalScrollBarVisibility="Auto">
<ListView HorizontalAlignment="Center" ItemsSource="{x:Bind ImagePages, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="BitmapImage">
<Image Source="{x:Bind }" Margin="0 2" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
</ScrollViewer>
For starters, the ItemAppearing property is not the behavior you are looking for. The ItemAppearing event for the ListView in Xamarin Forms is fired when the list item is rendered. For a small list this event will be fired for all items immediately. The equivalent event in UWP is ListView.ChoosingItemContainer event which like the ItemAppearing event, unless the ListView is virtualized is fired for all items in the list. Even for a large virtualized list, it is fired for several pages of items.
This is not what you want. As I understand it, you want to know the image that is visible at the top of the list view when the list is scrolled. Here is how to do that.
First of all. Get rid of the ScrollViewer. The ListView already has a ScrollViewer inside of it.
<ListView x:Name="listViewImage" Grid.Row="0" HorizontalAlignment="Center" ItemsSource="{x:Bind ImagePages, Mode=OneWay}"
Loaded="listViewImage_Loaded">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="BitmapImage">
<Image Source="{x:Bind }" Margin="0 2"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
Note that I have named the ListView and I have added a Loaded event handler. In this handler, find the ScrollViewer inside the ListView and attach a handler to the ViewChanged event.
private void listViewImage_Loaded(object sender, RoutedEventArgs e)
{
Border b = VisualTreeHelper.GetChild(listViewImage, 0) as Border;
ScrollViewer sv = b.Child as ScrollViewer;
sv.ViewChanged += Sv_ViewChanged;
}
In the view changed handler, find the first visible ListViewItem and get its index in the collection. This is what you want.
private void Sv_ViewChanged(object sender, ScrollViewerViewChangedEventArgs e)
{
ScrollViewer sv = sender as ScrollViewer;
GeneralTransform gt = sv.TransformToVisual(this);
Point p = gt.TransformPoint(new Point(0, 0));
List<UIElement> list = new List<UIElement>(VisualTreeHelper.FindElementsInHostCoordinates(p, sv));
ListViewItem item = list.OfType<ListViewItem>().FirstOrDefault();
if(item != null)
{
int index = listViewImage.IndexFromContainer(item);
Debug.WriteLine("Visible item at top of list is " + index);
}
}

How to detect list view scrolling direction in xamarin forms

I have tried to detect the scrolling direction of the list view. My requirement is need to implement different functionality while list view scrolling up and scrolling down. Please suggest any idea for detecting list view scrolling direction. I have tried below syntax in my list view.
Sample code:
<StackLayout>
<Label x:Name="Direction" />
<ListView ItemsSource="{Binding Items}" HasUnevenRows = "true" ItemAppearing="Handle_ItemAppearing" IsPullToRefreshEnabled = "true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text = "{Binding}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
I don't think you can do it by default, you can only act on a item that is appearing or disappearing. So, you either need to work with that by creating some code which gets the index of (dis)appearing items and and see if the indexes are getting higher or lower to determine whether someone is scrolling up or down. Or you need to hook up a custom renderer, but I'm not sure the native controls have anything to detect this either.
I've whipped up a very basic example for you, you can find the full code here.
Basically hook into the event available, keep track of the last index in a class variable and compare it to the current index of the item that is appearing.
private void Handle_ItemAppearing (object sender, Xamarin.Forms.ItemVisibilityEventArgs e)
{
var currentIdx = Items.IndexOf ((string)e.Item);
if (currentIdx > _lastItemAppearedIdx)
Direction.Text = "Up";
else
Direction.Text = "Down";
_lastItemAppearedIdx = Items.IndexOf ((string)e.Item);
}
In this code I simply show it in a Label, but of course you can create some enum to return or fire an event or something to make the code some more reusable. Here is the code in action:
Recently came through this problem and fixed it this way:
<StackLayout>
<Label x:Name="Direction" />
<ListView ItemsSource="{Binding Items}" HasUnevenRows = "true" ItemAppearing="Handle_ItemAppearing" ItemDisappearing="Handle_ItemDisappearing" IsPullToRefreshEnabled = "true">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Label Text = "{Binding}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
string ScrollingDirection;
int visibleTabIndex;
int disappearingTabIndex;
public async void Handle_ItemAppearing(object sender, ItemVisibilityEventArgs e)
{
var visibleTab = e.Item;
visibleTabIndex = MyItemsList.IndexOf(visibleTab);
if (disappearingTabIndex > visibleTabIndex) ScrollingDirection = "DOWN";
else ScrollingDirection = "UP";
}
public async void Handle_ItemDisappearing(object sender, ItemVisibilityEventArgs e)
{
var invisibleTab = e.Item as TicketsList;
disappearingTabIndex = tvm.Tickets.IndexOf(invisibleTab);
}

Binding to the SelectedItem in a ListBox which is in a DataTemplate for a ContentControl

Using an MVVM approach, I have a View that contains a ListBox and also a Grid in which I want to display information about the SelectedItem in the ListBox. I want to set the DataContext for the Grid to the SelectedItem.
However, the ListBox is buried as follows: A ContentControl that is bound to a DataTemplate that is a UserControl View that contains the ListBox.
Here is the MainWindow Grid that I'm not sure how to bind:
<Grid DataContext="{Binding ElementName=MyList, ????}">
Here is the ContentControl in the same View:
<ContentControl x:Name="MyList"
Content="{Binding}"
ContentTemplate="{StaticResource MyListTemplate}"/>
Here is the Data Template in the same View:
<Window.Resources>
<DataTemplate x:Key="MyListTemplate">
<v:MyListView/>
</DataTemplate>
</Window.Resources>
Here is MyListView:
<UserControl>
<ListBox Name="MyListBox" ItemsSource="{Binding ItemList}"/>
</UserControl>
I am adding to code I wrote a couple of years ago and have been away from WPF for a while, so alas, I am rusty on my data binding. I have been trying to add a SelectedItem property to the view model for MyListView and/or the MainWindow. I expect this may require RelativeSource.
Doh! I was forgetting to specify the OnPropertyChanged call for my property.
In the UserControl ListBox, I needed this:
ItemsSource="{Binding ItemList}" SelectedItem="{Binding MySelectedItem}"
In the main window view model, I needed this:
public MyItemViewModel MySelectedItem
{
get { return _mySelectedItem; }
set
{
_mySelectedItem = value;
OnPropertyChanged("MySelectedItem");
}
}
Then, in the main window, the binding is simply:
<Grid DataContext="{Binding MySelectedItem}">

Silverlight 4 DataGrid LoadingRow event using MVVM-Light EventToCommand not firing?

I'm using the MVVM-Light EventToCommand to try and implement a pre-fetching mechanism from my ViewModel, using the sample code for EventToCommand that's posted on the MVVM Light codeplex site.
Unfortunately the command doesn't seem to fire, even though the MouseMove event which I used as my model does fire fine.
Am I missing something funky about the DataGrid LoaddingRow event that means this will never work?
Here's my XAML (with MouseMove event artificially added to the mix to prove out the basics):
<sdk:DataGrid x:Name="TaskDataGrid"
AutoGenerateColumns="True" CanUserReorderColumns="False"
CanUserResizeColumns="False" ItemsSource="{Binding UserTasks}">
<!-- LoadingRow="TaskDataGrid_LoadingRow"> -->
<i:Interaction.Triggers>
<i:EventTrigger EventName="LoadingRow">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding CheckForPrefetchCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="MouseMove">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding MoveMouseCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
etc.
Here's the code in my ViewModel:
public RelayCommand<MouseEventArgs> MoveMouseCommand
{
get;
private set;
}
public RelayCommand<DataGridRowEventArgs> CheckForPrefetchCommand
{
get;
private set;
}
and in the constructor for the ViewModel the following gets called
CheckForPrefetchCommand = new RelayCommand<DataGridRowEventArgs>(e =>
{
// Do stuff here
int rowCount = e.Row.GetIndex();
});
MoveMouseCommand = new RelayCommand<MouseEventArgs>(e =>
{
var element = e.OriginalSource as UIElement;
var point = e.GetPosition(element);
string temp = string.Format("Position: {0}x{1}", point.X, point.Y);
});
The code for the MouseMove is hit, the code for the LoadingRow isn't. What am I missing?
It's not the first time I hear this complaint about some DataGrid events. I didn't have time to look into it, but I think there is something wrong with that control. I will check with MSFT and get back to you.
Cheers,
Laurent
I have this problem with WPF.
After many attempts, i found a solution but it's still not logical for me.
the solution is to call the Event trigger two time for the same event LoadingRow.
it works for me with some things to adjust.
I don't know if my proposition can help Mr LBugnion to solve the problem, Any way i share it with you.
<i:Interaction.Triggers>
<i:EventTrigger EventName="LoadingRow">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding CheckForPrefetchCommand}" />
</i:EventTrigger>
<i:EventTrigger EventName="LoadingRow">
<cmd:EventToCommand PassEventArgsToCommand="True"
Command="{Binding CheckForPrefetchCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>

Resources