Hello Telerik,
I have an issue when I try using your IsBusy property inside a grid.
Happens that the panel won't disappear. I tried using several of those "Loaded" events to make it happen manually (grid.IsBusy = false;), but then it won't even show at all.
I am using virtualization and infinite scrolling in my grid.
I just need a solution to hide the spinner when the data finish loading.
here is my code:
MainWindow.xaml
<Window x:Class="TelerikVirtualization.MainWindow" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" Title="MainWindow" Height="900" Width="700" > <Window.Resources> <Style x:Key="VitorStyle" TargetType="telerik:RadGridView" > <Setter Property="AutoGenerateColumns" Value="False"></Setter> <Setter Property="FilteringMode" Value="FilterRow"></Setter> </Style> </Window.Resources> <Grid> <Grid.Resources> <DataTemplate x:Key="RowDetailsTemplate"> <telerik:RadGridView Name="playersGrid" Style="{StaticResource VitorStyle}" IsBusy="True" ItemsSource="{Binding Children}" > <telerik:RadGridView.ControlPanelItems> <telerik:ControlPanelItem ButtonTooltip="Column chooser"> <telerik:ControlPanelItem.Content> <ListBox ItemsSource="{Binding Columns}" BorderThickness="0"> <ListBox.ItemTemplate> <DataTemplate> <CheckBox Content="{Binding Header, Mode=OneWay}" IsChecked="{Binding IsVisible, Mode=TwoWay}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </telerik:ControlPanelItem.Content> </telerik:ControlPanelItem> </telerik:RadGridView.ControlPanelItems> <telerik:RadGridView.Columns> <telerik:GridViewDataColumn DataMemberBinding="{Binding ID}"/> <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"/> <telerik:GridViewDataColumn DataMemberBinding="{Binding ParentID}"/> </telerik:RadGridView.Columns> </telerik:RadGridView> </DataTemplate> </Grid.Resources> <telerik:RadGridView Name="RadGridView" ItemsSource="{Binding View}" Style="{StaticResource VitorStyle}" IsBusy="True" RowDetailsTemplate="{StaticResource RowDetailsTemplate}" AutoGenerateColumns="False"> <telerik:RadGridView.Columns> <telerik:GridViewToggleRowDetailsColumn/> <telerik:GridViewDataColumn DataMemberBinding="{Binding ID}"/> <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"/> <telerik:GridViewDataColumn DataMemberBinding="{Binding UnitPrice}" Header="UnitPrice" /> <telerik:GridViewDataColumn DataMemberBinding="{Binding Date}" Header="Date" DataFormatString="{}{0:dd/MM/yyyy}"/> <telerik:GridViewDataColumn DataMemberBinding="{Binding Discontinued}"/> </telerik:RadGridView.Columns> <telerik:RadGridView.ControlPanelItems> <telerik:ControlPanelItem ButtonTooltip="Column chooser"> <telerik:ControlPanelItem.Content> <ListBox ItemsSource="{Binding Columns}" BorderThickness="0"> <ListBox.ItemTemplate> <DataTemplate> <CheckBox Content="{Binding Header, Mode=OneWay}" IsChecked="{Binding IsVisible, Mode=TwoWay}" /> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </telerik:ControlPanelItem.Content> </telerik:ControlPanelItem> </telerik:RadGridView.ControlPanelItems> </telerik:RadGridView> </Grid></Window>MainWindow.xaml.cs
using System.ComponentModel;using System.Windows;namespace TelerikVirtualization{ /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { BackgroundWorker worker = new BackgroundWorker(); public MainWindow() { InitializeComponent(); DataContext = new ViewModel(); } }ViewModel.cs *(install Fody.PropertyChanged nugget to make have it compiling)
using PropertyChanged;using System;using System.Collections.Generic;using System.Collections.ObjectModel;using Telerik.Windows.Data;using System.Linq;using System.Collections;namespace TelerikVirtualization{ [ImplementPropertyChanged]* public class ViewModel { public VirtualQueryableCollectionView View { get; set; } Controller controller; public ViewModel() { controller = new Controller(); View = new VirtualQueryableCollectionView(controller.GetList()) { LoadSize = 10 }; } } }Controller.cs
using System; using System.Linq;namespace TelerikVirtualization{ public class Controller { public IQueryable GetList() { DataClasses1DataContext context = new DataClasses1DataContext(); var result = from x in context.MyTables select new MyTableEntity() { Date = x.Date.GetValueOrDefault(DateTime.Now), Name = x.Name, UnitPrice = x.UnitPrice.GetValueOrDefault(0), id = x.ID, Discontinued = x.Discontinued, Children = (from y in context.MyChildTables where y.ParentID == x.ID select new MyChildTableEntity { ID = y.ID, Name = y.Name, ParentID = y.ParentID }) }; return result; } } public class MyTableEntity { public int id { get; set; } public string Name { get; set; } public decimal UnitPrice { get; set; } public DateTime Date { get; set; } public object Children { get; set; } public bool ? Discontinued { get; set; } } public class MyChildTableEntity { public int ID { get; set; } public string Name { get; set; } public int ? ParentID { get; set; } } }
Thank you.
24 Answers, 1 is accepted
The correct approach in this scenario would be to set RadGridView's IsBusy property to True and then return it to False in the GridView's DataLoaded event.
public MainWindow() { InitializeComponent(); DataContext = new ViewModel(); this.RadGridView.DataLoaded += RadGridView_DataLoaded; } private void RadGridView_DataLoaded(object sender, EventArgs e) { this.RadGridView.IsBusy = false; }Please let me know if this answers your question. Don't hesitate to contact us again should any further questions or concerns arise.
Regards,
Dilyan Traykov
Telerik
Hi Dilyan.
If I use that code, the spinner won't show at all.
please try to reproduce my scenario on your side, you have my code
thank you
I did try to reproduce your scenario, but the behavior I get is expected. The reason the BusyIndicator is not shown is that RadGridView loads the items instantaneously. To simulate the loading of items, I've added a 2-second delay. You can see that once the items are actually loaded, the indicator is hidden.
I'm attaching a modified version of your project to my reply. Please let me know if I've missed something important.
Regards,
Dilyan Traykov
Telerik
but if I modify your sample and remove that timer, the list will take some time to load (cos its 1 million rows), but wont show the spinner...
can you try that scenario?
thank you
I've modified my sample project and attached it to my reply. It makes use of the ItemsLoading and ItemsLoaded events of the VirtualQueryableCollectionView and displays the IsBusyIndicator when necessary. Please note that with this approach, the IsBusyIndicator will be shown each time the ItemsLoading is called.
Could you please have a look at the attached project and let me know if this approach would work for you?
I would also like to ask - is there a specific reason you're using a VirtualQueryableCollectionView? If that is not the case, maybe I can offer another solution based on your specific requirements.
Regards,
Dilyan Traykov
Telerik
Yes there is:
I followed your documentations regarding an endless scrolling (virtualization load) method. because your pagination via RadPageControl is broken when we apply the filter on the grid.
the endless scrolling works really fine with the filter and everything
I will give your solution a try and return in a minute
It is WORKING!!!
Thank you once more
There is just one detail that is missing:
the spinner doesn't "spin"
it only shows there, without animation.
what's wrong?
Such behavior would be expected, as both the animation and the data loading are executed on the UI thread. You need to move the time consuming operation on a separate thread. This can be achieved by using a Background Worker. You may also find the How to use WPF Background Worker StackOverflow thread useful.
Hope this helps.
Regards,
Stefan X1
Telerik
Hi Stefan
The logic of the backgroundworker is reasonable to solve this problem. but it won't match with Dilyan Traykov last solution.
because it needs to use the fully initialized View (list) and set the View_ItemsLoading and View_ItemsLoaded events upon it
when I use the BackgroundWorker, it will simply throw me a null exception
I will need a little more time to search for a solution for your scenario, but I will get back to you as soon as possible.
Regards,
Dilyan Traykov
Telerik
Thank you very much Dilyan.
I will be looking forward to hear from you
Thank you for your patience.
Another approach I can suggest is to wrap your RadGridView in a RadBusyIndicator with a DisplayAfter property set to 0​ and then set its (rather than RadGridView's) IsBusy property in the ItemsLoading and ItemsLoaded events:
<telerik:RadBusyIndicator Name="busyIndicator" IsBusy="True" DisplayAfter="0"> <telerik:RadGridView Name="RadGridView" /></telerik:RadBusyIndicator>private void View_ItemsLoaded(object sender, VirtualQueryableCollectionViewItemsLoadedEventArgs e){ this.busyIndicator.IsBusy = false;}private void View_ItemsLoading(object sender, VirtualQueryableCollectionViewItemsLoadingEventArgs e){ this.busyIndicator.IsBusy = true;}Please let me know if you're satisfied with the result from this approach.
Regards,
Dilyan Traykov
Telerik
FLAWLESS!
Thank you very much!
I must retract what I have just said.
The solution (actually both of them) fails when grouping.
But it will still do for now. But please verify that further on...
I might need to come back to this ticket later
In order to group the items correctly, the VirtualQueryableCollectionView needs to load all the items beforehand and the ItemsLoading and ItemsLoaded events do not get fired.
Please let me know if this clarifies things for you.
Regards,
Dilyan Traykov
Telerik
Hey Dilyan,
Yes it does. And it also explains why the performance is not the best when grouping...
So there is no way of using a IsBusy indicator for the case?
I tried handling the Grouping and Grouped events, for no use
If you want to display the BusyIndicator when grouping and expanding the groups, you can use the following event handlers, which seem to be working fine at my end:
public MainWindow(){ InitializeComponent(); DataContext = new ViewModel(); var view = (this.DataContext as ViewModel).View; view.ItemsLoading += View_ItemsLoading; view.ItemsLoaded += View_ItemsLoaded; this.RadGridView.Grouping += RadGridView_Grouping; this.RadGridView.Grouped += RadGridView_Grouped; this.RadGridView.GroupRowIsExpandedChanging += RadGridView_GroupRowIsExpandedChanging; this.RadGridView.GroupRowIsExpandedChanged += RadGridView_GroupRowIsExpandedChanged;}private void RadGridView_GroupRowIsExpandedChanged(object sender, Telerik.Windows.Controls.GridView.GroupRowEventArgs e){ this.busyIndicator.IsBusy = false;}private void RadGridView_GroupRowIsExpandedChanging(object sender, Telerik.Windows.Controls.GridView.GroupRowCancelEventArgs e){ this.busyIndicator.IsBusy = true;}private void RadGridView_Grouped(object sender, GridViewGroupedEventArgs e){ this.busyIndicator.IsBusy = false;}private void RadGridView_Grouping(object sender, GridViewGroupingEventArgs e){ this.busyIndicator.IsBusy = true;}private void View_ItemsLoaded(object sender, VirtualQueryableCollectionViewItemsLoadedEventArgs e){ this.busyIndicator.IsBusy = false;}private void View_ItemsLoading(object sender, VirtualQueryableCollectionViewItemsLoadingEventArgs e){ this.busyIndicator.IsBusy = true;}I've attached a modified version of my sample project to demonstrate this. Could you verify that you're using the same approach?
Regards,
Dilyan Traykov
Telerik
Hello Dilyan.
I wish I could give you good news, but I used your sample and I couldn't get it to run.
but as I noticed it approaches a slight different scenario, I decided to change is slightly to run it and get closer to my scenario:
Here is what I changed:
Controller.cs
public IQueryable GetList(){ var context = new DataClasses1DataContext(); var result = context.MyTables; return result.AsQueryable();}MainWindow.xaml:
<Window x:Class="TestRadGridView.MainWindow" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" xmlns:my="clr-namespace:TestRadGridView" Title="MainWindow" Height="700" Width="700"> <Window.Resources> <Style x:Key="VitorStyle" TargetType="telerik:RadGridView" > <Setter Property="AutoGenerateColumns" Value="False"></Setter> <Setter Property="FilteringMode" Value="FilterRow"></Setter> </Style> </Window.Resources> <Grid> <telerik:RadBusyIndicator Name="busyIndicator" IsBusy="True" DisplayAfter="0"> <telerik:RadGridView Name="RadGridView" ItemsSource="{Binding View}" AutoGenerateColumns="True"> </telerik:RadGridView> </telerik:RadBusyIndicator> </Grid></Window>And I added a Lint to SQL (dbml) file containing only one table (1 million rows on it. each with a random name and some random columns)
This is it. And the grouping won't show the Spinner.
I'm reattaching the modified project. At my end, it successfully displays the BusyIndicator once I group the items. Could you please have a look and let me know how this goes at your end?
Regards,
Dilyan Traykov
Telerik
sorry but your sample doesn't reflect my scenario.
My last post shows how to do so.
- linq to sql
- 1 million rows
I have modified my project accordingly, but everything is still working as expected. Could you please modify the attached project or maybe send over a sample project of your own that demonstrates the behavior you're observing at your end?
Thank you in advance for your cooperation on the matter.
Regards,
Dilyan Traykov
Telerik
Hi raneesras,
As per your request, I've prepared a small sample project demonstrating how to bind the IsBusy property of the control to a property in your viewmodel and use this property to display the indicator while the data is loading.
Please have a look and let me know if you find this example helpful.
Regards,
Dilyan Traykov
Progress Telerik