Using MVVM and Community Toolkit, I have a ContentPage (RentalPropertyHomePage) with a ViewModel (RentalPropertyHomePageVM), This ContentPage has a button bound to a RelayCommand and it has a ContentView (RentalPropertyListView) with it's ViewModel (RentalPropertyListVM). RentalPropertyHomePageVM has a RelayCommand which shows a PopUp. The ContentView (RentalPropertyListView) has CollectionView with the SelectedItem bound to an ObseveableProperty in it's ViewModel (RentalPropertyListVM). The DataTemplate for the CollectionView has a Button defined on it which binds to the RelayCommand in the VM of the parent Page (RentalPropertyHomePageVM) and happily sends the command the current item as the Parameter. I want to send that SelectedItem as the Parameter when I click the button which is defined on the parent Page.
Somewhat simplified XAML ...
<ContentPage x:Class="PropertyManagement.RentalProperties.ContentPages.RentalPropertyHomePage" >
<VerticalStackLayout
<Button Command="{Binding ShowEditPropertyCommand}" CommandParameter="{Binding .How do I get the selectedItem from the collectionview??}" Text="Edit" />
<content:RentalPropertyListView />
</VerticalStackLayout>
</ContentPage>
Relevant ViewModel code
[RelayCommand]
private async Task ShowEditProperty(RentalPropertyDetail rentalPropertyDetail)
{
// is a property selected in the list?
if (rentalPropertyDetail != null)
{
popupEdit = new(); // create new popup each time
var result = await Shell.Current.CurrentPage.ShowPopupAsync(popupEdit);
if (result is int theResult)
await showToast(theResult);
}
}
<ContentView x:Class="PropertyManagement.RentalProperties.ContentViews.RentalPropertyListView" >
<CollectionView HorizontalOptions="Center" ItemsSource="{Binding ObservableCollectionOfRentalProperties}"
SelectionMode="Single" SelectedItem="{Binding SelectedProperty}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="models:RentalPropertyDetail">
<Grid ColumnDefinitions="*, 125" >
<Label Grid.Column="0" Text="{Binding Address}" />
<Label Grid.Column="1" Text="{Binding PurchaseCost, StringFormat='{0:C0}'}" />
<Button Grid.Column="3" ImageSource="pencil.png"
Command="{Binding Source={RelativeSource AncestorType={x:Type ContentPage}}, Path=BindingContext.ShowEditPropertyCommand }" CommandParameter="{Binding .}" />
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ContentView>
Code Behind
RentalPropertyListViewModel vm = new RentalPropertyListViewModel();
public RentalPropertyListView()
{
InitializeComponent();
BindingContext = vm;
}
Relevant VM code
[ObservableProperty]
private ObservableCollection<RentalPropertyDetail> _observableCollectionOfRentalProperties;
[ObservableProperty]
RentalPropertyDetail selectedProperty;
How do I pass a selected item from a collection view into a command that is in its parent page? It appears that it can be done using messaging and sending objects around but that doesn't seem the best solution, not to me anyway.
Ideally, they should share a ViewModel - but if you absolutely need RentalPropertyListView to be self-contained, other than the option mentioned of messaging, you could consider adding a bindable OneWayToSource SelectedListItem property to RentalPropertyListView - so it propagates that value to the parent VM every time it's updated from within the view.