Detecting If Row Detail Is Expanded or Collapsed in DataGrid
Environment
| Product | Version | Author | | --- | --- | | DataGrid for .NET MAUI | 7.0.0 | Dobrinka Yordanova|
Description
In a MAUI application using the DataGrid, I need to detect when a row detail is expanded or collapsed while following the MVVM pattern.
This KB article also answers the following questions:
- How can I listen to row detail state changes in a DataGrid?
- Is there a way to bind the expansion state of row details in DataGrid to a ViewModel?
- Can I use MVVM to track the expansion and collapse of row details in DataGrid?
Solution
To detect when a row detail is expanded or collapsed in the DataGrid for MAUI using MVVM, you can employ the following approaches:
- Using the
ExpandedRowDetails
collection - Using the
ToggleRowDetailsButtonTap
command
Approach 1: Using the ExpandedRowDetails
Collection
1. Bind the ExpandedRowDetails
property of the DataGrid to an observable collection in the ViewModel. This collection holds the items for which the row details are currently expanded.
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="TemplateForRowDetails">
<VerticalStackLayout BackgroundColor="#F2EFF9"
Padding="12">
<Label Text="{Binding Country}" />
<Label Text="{Binding Capital}" />
<Label Text="{Binding Details}" />
</VerticalStackLayout>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<telerik:RadDataGrid x:Name="dataGrid"
ItemsSource="{Binding Items}"
ExpandedRowDetails="{Binding ExpandedItems}"
AutoGenerateColumns="False"
RowDetailsTemplate="{StaticResource TemplateForRowDetails}">
<telerik:RadDataGrid.Columns>
<telerik:DataGridToggleRowDetailsColumn />
<telerik:DataGridTextColumn PropertyName="Country" />
</telerik:RadDataGrid.Columns>
</telerik:RadDataGrid>
</Grid>
2. Monitor the CollectionChanged
event of the observable collection. Additions to the collection indicate row detail expansions, while removals indicate collapses. Implement the required logic within the event handler to respond to these changes.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = new ViewModel();
}
}
public class ViewModel : NotifyPropertyChangedBase
{
public ViewModel()
{
var items = new ObservableCollection<Data>
{
new Data { Country = "India", Capital = "New Delhi" , Details = "New Delhi is the capital of India and a part of the National Capital Territory of Delhi (NCT). New Delhi is the seat of all three branches of the Government of India, hosting the Rashtrapati Bhavan, Sansad Bhavan, and the Supreme Court."},
new Data { Country = "South Africa", Capital = "Cape Town", Details = "Cape Town is South Africa's oldest city. It serves as the country's legislative capital, being the seat of the South African Parliament.It is the country's second-largest city (after Johannesburg) and the largest in the Western Cape."},
new Data { Country = "Nigeria", Capital = "Abuja" , Details = "Abuja is the capital city of Nigeria. When it was decided to move the national capital from Lagos in 1976, a capital territory was chosen for its location near the centre of the country. The planned city is located in the centre of what is now the Federal Capital Territory." },
new Data { Country = "Singapore", Capital = "Singapore" , Details = "Singapore is the capital city of the Republic of Singapore. It occupies the southern part of Singapore Island. Its strategic position on the strait between the Indian Ocean and South China Sea, complemented by its deepwater harbour, has made it the largest port in Southeast Asia." }
};
this.Items = items;
this.ExpandedItems = new ObservableCollection<Data>();
// Approach 1
this.ExpandedItems.CollectionChanged += ExpandedItems_CollectionChanged;
}
// Approach 1
private void ExpandedItems_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
// your logic here
}
else if(e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove)
{
// your logic here
}
}
public ObservableCollection<Data> Items { get; set; }
public ObservableCollection<Data> ExpandedItems { get; set; }
}
public class Data
{
public string Country { get; set; }
public string Capital { get; set; }
public string Details { get; set; }
}
Approach 2: Using the ToggleRowDetailsButtonTap
Command
1. Utilize the ToggleRowDetailsButtonTap
command provided by the DataGrid. This command is triggered whenever the toggle button for row details is tapped. In the command's execution logic, add a flag or a mechanism to check whether the item related to the toggled row detail is present in the ExpandedRowDetails
collection. An item's presence indicates an expansion, while its absence indicates a collapse.
Implement the necessary logic based on this condition to handle the expansion or collapse state.
public class MyToggleRowDetailsButtonTapCommand : DataGridCommand
{
public MyToggleRowDetailsButtonTapCommand()
{
Id = DataGridCommandId.ToggleRowDetailsButtonTap;
}
public override bool CanExecute(object parameter)
{
return true;
}
public override void Execute(object parameter)
{
// flag
bool wasExpanded = this.Owner.ExpandedRowDetails.Contains(parameter);
this.Owner.CommandService.ExecuteDefaultCommand(DataGridCommandId.ToggleRowDetailsButtonTap, parameter);
}
}
2. The ViewModel
and data model definition:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = new ViewModel();
}
}
public class ViewModel : NotifyPropertyChangedBase
{
public ViewModel()
{
var items = new ObservableCollection<Data>
{
new Data { Country = "India", Capital = "New Delhi" , Details = "New Delhi is the capital of India and a part of the National Capital Territory of Delhi (NCT). New Delhi is the seat of all three branches of the Government of India, hosting the Rashtrapati Bhavan, Sansad Bhavan, and the Supreme Court."},
new Data { Country = "South Africa", Capital = "Cape Town", Details = "Cape Town is South Africa's oldest city. It serves as the country's legislative capital, being the seat of the South African Parliament.It is the country's second-largest city (after Johannesburg) and the largest in the Western Cape."},
new Data { Country = "Nigeria", Capital = "Abuja" , Details = "Abuja is the capital city of Nigeria. When it was decided to move the national capital from Lagos in 1976, a capital territory was chosen for its location near the centre of the country. The planned city is located in the centre of what is now the Federal Capital Territory." },
new Data { Country = "Singapore", Capital = "Singapore" , Details = "Singapore is the capital city of the Republic of Singapore. It occupies the southern part of Singapore Island. Its strategic position on the strait between the Indian Ocean and South China Sea, complemented by its deepwater harbour, has made it the largest port in Southeast Asia." }
};
this.Items = items;
this.ExpandedItems = new ObservableCollection<Data>();
}
public ObservableCollection<Data> Items { get; set; }
public ObservableCollection<Data> ExpandedItems { get; set; }
}
public class Data
{
public string Country { get; set; }
public string Capital { get; set; }
public string Details { get; set; }
}
3. Define the DataGrid:
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="TemplateForRowDetails">
<VerticalStackLayout BackgroundColor="#F2EFF9"
Padding="12">
<Label Text="{Binding Country}" />
<Label Text="{Binding Capital}" />
<Label Text="{Binding Details}" />
</VerticalStackLayout>
</DataTemplate>
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<telerik:RadDataGrid x:Name="dataGrid"
ItemsSource="{Binding Items}"
ExpandedRowDetails="{Binding ExpandedItems}"
AutoGenerateColumns="False"
RowDetailsTemplate="{StaticResource TemplateForRowDetails}">
<telerik:RadDataGrid.Columns>
<telerik:DataGridToggleRowDetailsColumn />
<telerik:DataGridTextColumn PropertyName="Country" />
</telerik:RadDataGrid.Columns>
<telerik:RadDataGrid.Commands>
<local:MyToggleRowDetailsButtonTapCommand />
</telerik:RadDataGrid.Commands>
</telerik:RadDataGrid>
</Grid>
Both approaches allow for handling row detail expansion and collapse states in a MVVM-compliant manner, enabling you to perform actions or update the UI accordingly.