I'm trying to figure out how you can get the index from a list inside XAML.
Context
A product has multiple specification categories/groups which contain the specification details.
- Product & Ingrediƫnten are the specification groups.
- Land van afkomst : Nederland are the specs details
In the XAML code, I'm using a nested list. The application needs to pass the Index so the users can delete and add specifications correctly.
The index at Binding Source="0" /> & CommandParameter="0" needs to be passed instead of "0".
<StackLayout BindableLayout.ItemsSource="{Binding Product.Specifications}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout>
<Entry Text="{Binding Title, Mode=TwoWay}" />
<StackLayout BindableLayout.ItemsSource="{Binding SpecificationDetails}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".44*" />
<ColumnDefinition Width=".44*" />
<ColumnDefinition Width=".12*" />
</Grid.ColumnDefinitions>
<Entry Grid.Row="0"
Grid.Column="0"
Text="{Binding Title}"
Style="{StaticResource spec-entry-style}" />
<Entry Grid.Row="0"
Grid.Column="1"
Text="{Binding Description}"
Style="{StaticResource spec-entry-style}" />
<!-- Delete specification detail -->
<Button Grid.Column="2"
Text="X"
Style="{StaticResource cancel-button-style}"
Command="{Binding Path=BindingContext.DeleteSpecificationEntryCommand, Source={x:Reference Page}}">
<Button.CommandParameter>
<MultiBinding Converter="{StaticResource SpecsConverter}">
<Binding Source="0" />
<Binding Path="." />
</MultiBinding>
</Button.CommandParameter>
</Button>
</Grid>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<!-- Add specification detail -->
<Button Text="Voeg specificatie toe"
Command="{Binding AddSpecicifationEntriesCommand}"
CommandParameter="0"
HorizontalOptions="Start" />
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
<!-- Add Specification group -->
<Button Text="Voeg nieuwe specificatie toe"
Command="{Binding AddNewSpecificationGroupCommand}" />
The specs group model:
public class SpecificationDbViewModel : INotifyPropertyChanged
{
private int _id;
private string _title;
private ObservableCollection<SpecificationDetailDbViewModel> _specificationDetails;
public int Id
{
get => _id;
set
{
_id = value;
RaisePropertyChanged(nameof(Id));
}
}
public string Title
{
get => _title;
set
{
_title = value;
RaisePropertyChanged(nameof(Title));
}
}
public ObservableCollection<SpecificationDetailDbViewModel> SpecificationDetails
{
get => _specificationDetails;
set
{
_specificationDetails = value;
RaisePropertyChanged(nameof(Title));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
The specs detail model:
public class SpecificationDetailDbViewModel : INotifyPropertyChanged
{
private int _id;
private string _title;
private string _description;
public int Id
{
get => _id;
set
{
_id = value;
RaisePropertyChanged(nameof(Id));
}
}
public string Title
{
get => _title;
set
{
_title = value;
RaisePropertyChanged(nameof(Title));
}
}
public string Description
{
get => _description;
set
{
_description = value;
RaisePropertyChanged(nameof(Description));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I'm using a MultiBinder converter to pass multiple values to the command. 1 method inside the ViewModel that removes the specifications:
private void ExecuteDeleteSpecificationEntryCommand(SpecificationDetailWithIndex specificationDetailWithIndex)
{
Product.Specifications[specificationDetailWithIndex.Index].SpecificationDetails.Remove(specificationDetailWithIndex.SpecificationDetailDbViewModel);
}
And you can also use groups in the list view btw.