This is a migrated thread and some comments may be shown as answers.

Override order event/Make a footer

2 Answers 145 Views
DataGrid
This is a migrated thread and some comments may be shown as answers.
Raphael
Top achievements
Rank 1
Raphael asked on 07 Dec 2018, 01:53 PM
Hello,

I'm using RadDataGrid component in my project and I have some questions that I do not find the answers neither on the forum or on the net.

Is it possible to override the sorting event in the goal to sort on our data source ? My use case is the following : I display a list in my RadDataGrid, when the user scrolls, the data loads with the load on demand. That's working like a charm ! But when he presses the header, the displayed data are sorted. What we want is to sort on all the dataset not only the displayed. So, is there a way to override the clic on the header or a workaround to do this ?

I got a second question, is it possible to include a footer in a RadDataGrid ? A fixed component like the headers but on the bottom of the RadDataGrid. The use case is the following : I got a RadDataGrid with 10-20 rows which contain numbers, I want a line highlighted as the one of the headers with the total of each columns of the RadDataGrid and which stay on the bottom even during a sort. Is that possible ?

I tried to put a Grid under the RadDataGrid but I can't get column's ActualWidth property, it's always set to 0. Like the SizeMode of my columns is not Fixed I can't use the Width property. Here how I try to get the width of a column when the RadDataGrid is displayed :
radDataGrid.Columns[0].ActualWidth


Thanks a lot for the time you spent to read this, I hope you can help me.

2 Answers, 1 is accepted

Sort by
0
Accepted
Lance | Manager Technical Support
Telerik team
answered on 07 Dec 2018, 09:26 PM
Hello Raphael,

I don't see a license on your account (trial or purchased), so I cant tell what version you're using, but I will assume the latest (2018.3.1122). If you are using your employer's copy, have them assign you as the licensed user here so you can open support tickets: Manage Licensed Users.

Okay, let me get right to the answers:

Sort Event

There's not Sort event to hook into, but you can hook into the SortDescriptors CollectionChanged event which is effectively the same thing.

DataGrid.SortDescriptors.CollectionChanged += SortDescriptors_CollectionChanged;
 
private void SortDescriptors_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    Debug.WriteLine($"SortDescriptorsChanged: {DataGrid.SortDescriptors?.Count}");
}


LoadOnDemand and sorting

Because you're using load on demand, the DataGrid's DataView (the internal collection that gets sorted/grouped/filtered) doesn't know about all the data. Therefore, it can only sort what it currently has in the ItemsSource. This is the main limitation of using any type of load on demand scenario.

Options:

1 - Remove Load On demand and use DataGrid sorting features

You can either load all the items and let the DataGrid sort them, or use load on demand and load pre-sorted data. You can't use both simultaneously.

2 - Sort the remote data and keep LoadOnDemand

One option to keep Load On Demand is to sort the original data set, usually done through the API or Database that supplies the data. Then, you reset the ItemSource, which will trigger the next fetch on the, now sort-defined, data source.

Conceptual Example of Remote Sorting

As a conceptual example, lets say the API accepts a sort parameter in the query string:

mysite.com/api/customers?startIndex=0&count=20&sort=first_name

Then when the LoadOnDemand Action is invoked, the startIndex and count parameters will be incremented by your app's increment logic, but each call to the API contains a sort parameter. Since the data from the API is already sorted, the DataGrid just loads the items in order.


Column Width

The trick for this is to just set a custom HeaderContentTemplate and get that element's width instead. Note that you'll need to add a few pixels to make up for the vertical ellipsis, but that always a fixed size.

Here's a simple example to show how the custom header is set with a simple view model property binding for the width:

<ContentPage ...>
 
    <ContentPage.BindingContext>
        <local:MainViewModel x:Name="ViewModel"/>
    </ContentPage.BindingContext>
 
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
 
        <telerikGrid:RadDataGrid x:Name="DataGrid"
                                 AutoGenerateColumns="False">
            <telerikGrid:RadDataGrid.Columns>
                <telerikGrid:DataGridTextColumn PropertyName="Country" HeaderText="Country">
                    <telerikGrid:DataGridTextColumn.HeaderContentTemplate>
                        <DataTemplate>
                            <Grid Width="{Binding CountryColumnWidth, Source={x:Reference ViewModel}, Mode=OneWayToSource}">
                                <Label Text="{Binding}"/>
                            </Grid>
                        </DataTemplate>
                    </telerikGrid:DataGridTextColumn.HeaderContentTemplate>
                </telerikGrid:DataGridTextColumn>
                <telerikGrid:DataGridTextColumn PropertyName="Capital" HeaderText="Capital" >
                    <telerikGrid:DataGridTextColumn.HeaderContentTemplate>
                        <DataTemplate>
                            <Grid Width="{Binding CapitalColumnWidth, Source={x:Reference ViewModel}, Mode=OneWayToSource}">
                                <Label Text="{Binding}" />
                            </Grid>
                        </DataTemplate>
                    </telerikGrid:DataGridTextColumn.HeaderContentTemplate>
                </telerikGrid:DataGridTextColumn>
            </telerikGrid:RadDataGrid.Columns>
        </telerikGrid:RadDataGrid>
 
        <Grid Grid.Row="1" HeightRequest="50">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="{Binding CountryColumnWidth, Source={x:Reference ViewModel}, Mode=OneWay}"/>
                <ColumnDefinition Width="{Binding CapitalColumnWidth, Source={x:Reference ViewModel}, Mode=OneWay}"/>
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
 
            <Grid BackgroundColor="Red"/>
            <Grid BackgroundColor="Green"
                  Grid.Column="1"/>
            <Grid BackgroundColor="Blue"
                  Grid.Column="2"/>
        </Grid>
    </Grid>
</ContentPage>

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
 
        DataGrid.ItemsSource = new List<Data>
        {
            new Data { Country = "India", Capital = "New Delhi"},
            new Data { Country = "South Africa", Capital = "Cape Town"},
            new Data { Country = "Nigeria", Capital = "Abuja" },
            new Data { Country = "Singapore", Capital = "Singapore" }
        };
 
        DataGrid.SortDescriptors.CollectionChanged += SortDescriptors_CollectionChanged;
    }
 
    private void SortDescriptors_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        Debug.WriteLine($"SortDescriptorsChanged: {DataGrid.SortDescriptors?.Count}");
    }
}
 
public class Data
{
    public string Country { get; set; }
    public string Capital { get; set; }
}
 
public class MainViewModel : BindableBase
{
    private double _countryColumnWidth;
    private double _capitalColumnWidth;
 
    public double CountryColumnWidth
    {
        // The only thing calling this getter is the extra Grid control, so we can add the additional pixels
        // for the column options vertical ellipsis
        get => _countryColumnWidth + 40;
        // The only thing calling the setter is the custom HeaderContentTemplate element
        set => SetProperty(ref _countryColumnWidth, value);
    }
 
    public double CapitalColumnWidth
    {
        get => _capitalColumnWidth;
        set => SetProperty(ref _capitalColumnWidth, value);
    }
}


Here is the result at runtime:



Sum

Your final question about calculating the sum to place in the footer area will also need to be done manually, but this is an easy LINQ methods to call.

Let's say in the previous example had a Population column instead of a Capital column, you can get the SUM for a column and set some Label Text value like this

PopulationSumLabel.Text = (DataGrid.ItemsSource as ObservableCollection<Data>).Sum(c => c.Population).ToString()



Regards,
Lance | Tech Support Engineer, Sr.
Progress Telerik
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Raphael
Top achievements
Rank 1
answered on 10 Dec 2018, 09:52 AM
Hello,

It's noted, I'll talk to him about it so that we can go through your support platform.

Thank you very much for all your explanations. They are clear and you even offer examples of implementation, it's perfect!

I will implement your answer in our project and come back to you in case I have a problem.

Thank you for your responsiveness, the time you took to respond and the clarity of your response.
Raphael


Translated with www.DeepL.com/Translator
Tags
DataGrid
Asked by
Raphael
Top achievements
Rank 1
Answers by
Lance | Manager Technical Support
Telerik team
Raphael
Top achievements
Rank 1
Share this question
or