14 Answers, 1 is accepted
I already answered this question in your support ticket. However I will copy/paste the same answer here so that others from the community can benefit from it.
Pull to refresh is a feature allowing end customers to manually update a list of items. This is an UI operation and it should not be triggered from code. If developers need to update that same list they should directly add items to the list's ItemsSource.
As for the other way, you can create a custom behavior which can be attached to the RadListView. That behavior can listen for the RefreshRequested event and can trigger your custom command as well as the EndRefresh() method. Using behavior does not break any MVVM approach and is frequently used.
If you ask if there is out of the box approach for implementing pull to refresh command - the answer is no. Currently we do not support such command. However, there are many third party behaviors (e.g. event to command behavior) that can fit your scenario. You can try looking for them as well.
Regards,
Pavel R. Pavlov
Telerik

Sorry
for hijacking this old post. I currently use behaviours to hook some ListView
commend to my Viewmodel. But can you point me the way to call the viewmodel
Event with ICommand AND do a EndRefresh() on the local side? DO you pass the
ListviewObject to the viewmodel for that?
Thanks

I am using this EventToCommand
public
class
EventToCommandBehavior : BehaviorBase<View>
{
Delegate eventHandler;
public
static
readonly
BindableProperty EventNameProperty = BindableProperty.Create (
"EventName"
,
typeof
(
string
),
typeof
(EventToCommandBehavior),
null
, propertyChanged: OnEventNameChanged);
public
static
readonly
BindableProperty CommandProperty = BindableProperty.Create (
"Command"
,
typeof
(ICommand),
typeof
(EventToCommandBehavior),
null
);
public
static
readonly
BindableProperty CommandParameterProperty = BindableProperty.Create (
"CommandParameter"
,
typeof
(
object
),
typeof
(EventToCommandBehavior),
null
);
public
static
readonly
BindableProperty InputConverterProperty = BindableProperty.Create (
"Converter"
,
typeof
(IValueConverter),
typeof
(EventToCommandBehavior),
null
);
public
string
EventName {
get
{
return
(
string
)GetValue (EventNameProperty); }
set
{ SetValue (EventNameProperty, value); }
}
public
ICommand Command {
get
{
return
(ICommand)GetValue (CommandProperty); }
set
{ SetValue (CommandProperty, value); }
}
public
object
CommandParameter {
get
{
return
GetValue (CommandParameterProperty); }
set
{ SetValue (CommandParameterProperty, value); }
}
public
IValueConverter Converter {
get
{
return
(IValueConverter)GetValue (InputConverterProperty); }
set
{ SetValue (InputConverterProperty, value); }
}
protected
override
void
OnAttachedTo (View bindable)
{
base
.OnAttachedTo (bindable);
RegisterEvent (EventName);
}
protected
override
void
OnDetachingFrom (View bindable)
{
base
.OnDetachingFrom (bindable);
DeregisterEvent (EventName);
}
void
RegisterEvent (
string
name)
{
if
(
string
.IsNullOrWhiteSpace (name)) {
return
;
}
EventInfo eventInfo = AssociatedObject.GetType ().GetRuntimeEvent (name);
if
(eventInfo ==
null
) {
throw
new
ArgumentException (
string
.Format (
"EventToCommandBehavior: Can't register the '{0}' event."
, EventName));
}
MethodInfo methodInfo =
typeof
(EventToCommandBehavior).GetTypeInfo ().GetDeclaredMethod (
"OnEvent"
);
eventHandler = methodInfo.CreateDelegate (eventInfo.EventHandlerType,
this
);
eventInfo.AddEventHandler (AssociatedObject, eventHandler);
}
void
DeregisterEvent (
string
name)
{
if
(
string
.IsNullOrWhiteSpace (name)) {
return
;
}
if
(eventHandler ==
null
) {
return
;
}
EventInfo eventInfo = AssociatedObject.GetType ().GetRuntimeEvent (name);
if
(eventInfo ==
null
) {
throw
new
ArgumentException (
string
.Format (
"EventToCommandBehavior: Can't de-register the '{0}' event."
, EventName));
}
eventInfo.RemoveEventHandler (AssociatedObject, eventHandler);
eventHandler =
null
;
}
void
OnEvent (
object
sender,
object
eventArgs)
{
if
(Command ==
null
) {
return
;
}
object
resolvedParameter;
if
(CommandParameter !=
null
) {
resolvedParameter = CommandParameter;
}
else
if
(Converter !=
null
) {
resolvedParameter = Converter.Convert (eventArgs,
typeof
(
object
),
null
,
null
);
}
else
{
resolvedParameter = eventArgs;
}
if
(Command.CanExecute (resolvedParameter)) {
Command.Execute (resolvedParameter);
}
}
static
void
OnEventNameChanged (BindableObject bindable,
object
oldValue,
object
newValue)
{
var behavior = (EventToCommandBehavior)bindable;
if
(behavior.AssociatedObject ==
null
) {
return
;
}
string
oldEventName = (
string
)oldValue;
string
newEventName = (
string
)newValue;
behavior.DeregisterEvent (oldEventName);
behavior.RegisterEvent (newEventName);
}
}
You need a reference to the RadListView in order to call EndRefresh.
How you pass that to the ViewModel is up to you, but since you already have a behavior set up, you can just pass the RadListView as the CommandParameter instead of the event args (event args is the default).
For example:
<
telerikDataControls:RadListView
x:Name
=
"radListView"
ItemsSource
=
"{Binding MyItems}"
IsPullToRefreshEnabled
=
"True"
>
<
telerikDataControls:RadListView.Behaviors
>
<
portable:EventToCommandBehavior
EventName
=
"RefreshRequested"
Command
=
"{Binding PullToRefreshCommand}"
CommandParameter
=
"{x:Reference radListView}"
/>
</
telerikDataControls:RadListView.Behaviors
>
</
telerikDataControls:RadListView
>
public
class
ViewModel
{
public
ViewModel()
{
PullToRefreshCommand =
new
Command(async (rlv) => await RefreshData(rlv));
}
private
async Task RefreshData(
object
obj)
{
// this just simulates a network delay
await Task.Delay(1000);
// 1 - refresh your data
MyItems.Add($
"Item {MyItems.Count + 1}"
);
// 2 - end refresh
(obj
as
RadListView)?.EndRefresh();
}
public
Command PullToRefreshCommand {
get
;
set
; }
public
ObservableCollection<
string
> MyItems {
get
;
set
; } =
new
ObservableCollection<
string
> {
"Item 1"
,
"Item 2"
,
"Item 3"
};
}
I've attached a demo using the above code.
If you have any further trouble, open a support ticket here, attach the code we can use to reproduce the problem and we'll investigate further.
Regards,
Lance | Tech Support Engineer, Sr.
Progress Telerik

Thanks, you code work great. But The PullToRefresh work only on IOS. In UWP I can't slide to make the refresh zone appears.
Any idea?
De we have a way to haev a template of the PullToRefresh zone? For now I only get an big black zone with a loading indicator. Can we write some text (like the last time we update the list)
If the UWP app is deployed to mobile device family, it should be working as expected. However on desktop, you'd need touch to pull it as the mouse won't trigger the gesture. In this case, you can dynamically show a refresh button if the runtime platform is UWP.
Regarding customizing the pull to refresh area, you'll need to write a custom renderer as we don't expose the API in Xamarin.Forms, see this forum thread for a discussion and example.
For your convenience, I've updated the cmeo to use the latest version and remove the deprecated code. Here's a short video of the attached demo at runtime and here's the entirety of the renderer in the AppDelegate class:
using
Foundation;
using
Telerik.XamarinForms.DataControls;
using
UIKit;
using
ListViewPullToRefreshStyle.iOS;
using
Xamarin.Forms;
using
Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(
typeof
(RadListView),
typeof
(CustomListViewRenderer))]
namespace
ListViewPullToRefreshStyle.iOS
{
[Register(
"AppDelegate"
)]
public
partial
class
AppDelegate : FormsApplicationDelegate
{
public
override
bool
FinishedLaunching(UIApplication app, NSDictionary options)
{
Forms.Init();
LoadApplication(
new
Portable.App());
return
base
.FinishedLaunching(app, options);
}
}
public
class
CustomListViewRenderer : Telerik.XamarinForms.DataControlsRenderer.iOS.ListViewRenderer
{
protected
override
void
OnElementChanged(ElementChangedEventArgs<RadListView> e)
{
base
.OnElementChanged(e);
this
.Control.PullToRefreshView.ActivityIndicator.ActivityIndicatorViewStyle = UIActivityIndicatorViewStyle.WhiteLarge;
// and or
this
.Control.PullToRefreshView.ActivityIndicator.Color = UIColor.White;
this
.Control.PullToRefreshView.BackgroundColor = UIColor.Green;
}
}
}
As far as using text instead of the busy indicator animation, this is not currently a feature. If you're familiar with Xamarin.iOS, you can create a subview and use UITextView to manually create it, but this is not supported and a completely custom approach which falls outside the scope of Telerik Support.
Lastly, you'll need to create custom renderers for each platform and keep in mind not all platforms have the same customization features for the PullToRefresh indicator and you'll have to account for these nuances. Here is the documentation for the other platforms: here for UI for UWP and here UI for Xamarin.Android.
If you'd like us to add an API that lets you customize it without a custom renderer, submit a feature request here.
Regards,
Lance | Tech Support Engineer, Sr.
Progress Telerik

[quote]Lance | Tech Support Engineer, Sr. said:Hi Pierre,
If the UWP app is deployed to mobile device family, it should be working as expected. However on desktop, you'd need touch to pull it as the mouse won't trigger the gesture. In this case, you can dynamically show a refresh button if the runtime platform is UWP.
[/quote]
It is a limitation of UWP itself? Or a limitation on Telerik RadListview?My app will be deployed on IOS and UWP (mobile and desktop). I can add a Refresh Button UWP view, but I got the sale problem with cellSwipe in the listview... Any workaround?
Correct, this isn't related to Xamarin or UI for Xamarin. It's a platform-specific approach, not necessarily a limitation, because many desktop PCs now have touchscreens. As a UWP developer you'd build your apps expecting certain inputs to be available and surface contextual interactions accordingly.
We have been adding some features to the native RadListView to overcome some of these like the Handle reorder mode for the RadListView. On desktop, the handle allows you to reorder the item with mouse.
There have been requests to bring more pointer base gestures to the native control, you can find the native control's home here on GitHub. Add an Issue to the repo here and requesting that swipe and pull to refresh to be supported. As you can see this Issue was the one that requested the Reorder mode support and was promptly added to the product.
Advanced Workaround
There is one workaround you can try, but it's a more advanced scenario, you could try to reroute pointer input into touch input (here's an example for WPF). I couldn't find any examples for UWP, but this is the Pointer input information you'd need to build it.
Regards,
Lance | Tech Support Engineer, Sr.
Progress Telerik

I use your solution for the listview SellSwipe too. I pass the LV instance to be able to do the EndItemSwipe().
But I can't detect the swipeOffset and know if the swipe is right or left. Normally in the code behind we got an ItemSwipeCompletedEventArgs that contains an e.Offset for that. But I can't see anything like that directly in the LV object.
For now I do:
private
async
void
OnItemSwipeCompleted(RadListView lv)
{
if
(lv.IsSwipingInProgress ==
true
)
{
await Task.Delay(1000);
var item = lv.SelectedItem;
var tt = lv.SwipeOffset;
lv.EndItemSwipe();
}
}
But lv.SwipeOffet contained the general offset information.
Do we have another way? Can we pass the ItemSwipeCompletedEventArgs when commanding?
Thanks
Yes, if you use an EventToCommandBehavior, you'll get the ItemSwipeCompletedEventArgs passed to the command's Action (take a look at the EventToCommandBehavior in my GitHub demo here).
Example
Here's a small demo to convey the approach:
In the View:
<
dataControls:RadListView
...>
<
dataControls:RadListView.Behaviors
>
<
behaviors:EventToCommandBehavior
EventName
=
"ItemSwipeCompleted"
Command
=
"{Binding MySwipeCommand}"
/>
</
dataControls:RadListView.Behaviors
>
</
dataControls:RadListView
>
In the ViewModel
public
class
ViewModel
{
public
ViewModel()
{
MySwipeCommand =
new
Command(ExecuteOnSwipeCompete);
}
public
Command MySwipeCommand {
get
; }
private
void
ExecuteOnSwipeComplete(
object
obj)
{
var args = obj
as
ItemSwipeCompletedEventArgs;
// this is the same args you get in a code-behind event handler
}
}
Further Assistance
If you have any trouble implementing it, please open a support ticket here and attach your code directly to the ticket (you have priority support). I will see the ticket come in and will investigate further.
Regards,
Lance | Tech Support Engineer, Sr.
Progress Telerik

Hello Lance,
Ok I understand that, but in this case, I lost the LV object so I can't do the EndItemSwipe. In you exemple can I get the "sender" object to?
Hello Pierre,
EventToCommand isn't designed to also pass the sender because this breaks MVVM. If you don't mind tightly coupling the view to the viewmodel, you can pass the RadListView reference to the view model in the page's code behind.
For example:
ViewModel
public
class
ViewModel
{
public
ViewModel()
{
MySwipeCommand =
new
Command(ExecuteOnSwipeCompete);
}
public
RadListView MyListViewReference {
get
;
set
; }
public
Command MySwipeCommand {
get
; }
private
void
ExecuteOnSwipeComplete(
object
obj)
{
var args = obj
as
ItemSwipeCompletedEventArgs;
// this is the same args you get in a code-behind event handler
MyListViewReference.xxx
}
}
View Markup
<
ContentPage..
>
<
telerik:RadListView
x:Name
=
"MyListView"
/>
</
ContentPage
>
View Code behind:
public
partial
class
MyPage : ContentPage
{
public
MyPage()
{
InitializeComponent();
(BindingContext
as
ViewModel).MyListViewReference =
this
.
MyListView
;
}
}
Regards, Lance | Tech Support Engineer, Sr.
Progress Telerik

The answers on this post are nasty hacks and this is disappointing from Telerik.
It's doubly disappointing because the out of the box Xamarin.Forms ListView has Commanding for PullToRefresh where as the RadListView does not - it's worse than the out of the box component in this area.
So here is once way to work around this:
```csharp
public interface IGridAdaptor
{
void Cancel();
void EndRefresh();
}
public class RadGridAdaptor : IGridAdaptor
{
private readonly PullToRefreshRequestedEventArgs _args;
private readonly RadListView _listView;
public RadGridAdaptor(PullToRefreshRequestedEventArgs args, RadListView listView)
{
_args = args;
_listView = listView;
}
public void Cancel()
{
_args.Cancel = true;
}
public void EndRefresh()
{
_listView.EndRefresh();
}
}
public class RadGridPullToRefreshArgsConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var args = value as PullToRefreshRequestedEventArgs;
var listView = parameter as RadListView;
return new RadGridAdaptor(args, listView);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
```
Then in your xaml:
```xml
<telerikDataControls:RadListView.Behaviors>
<b:EventToCommandBehavior EventName="RefreshRequested"
Command="{Binding RefreshCommand}"
EventArgsConverterParameter="{x:Reference listView}"
EventArgsConverter="{converters:RadGridPullToRefreshArgsConverter}"/>
</telerikDataControls:RadListView.Behaviors>
```
The idea is basically the `Behavior` handles the event, and then passes the Grid and the Event Args to a Converter.
The Converter creates an `IGridAdaptor` which wraps those, and can be passed into your `ICommand`. This way you can potentially switch the ListView implementation in future without having to refactor your commands, by implementing a new Converter.
The command accepts the `IGridAdaptor` as an argument does its business, then calls EndRefresh (or Cancel).
```
RefreshCommand = new DelegateCommand<IGridAdaptor>(async (arg) =>
{
await DoStuff();
_deviceService.BeginInvokeOnMainThread(() =>
{
arg.EndRefresh();
});
});
```
Be careful, you must call the EndRefresh() from a UI thread.
Initially the RadListView didn't have support for commands, which was why we had to suggest such workarounds. We understood the need for this and thus we've recently added MVVM Command support for all the relevant events.
You just need to add to the RadListView.Commands collection using an ID to identify which event the command is for (as opposed to directly wiring up the command to a property).
Here's a list of the available IDs:
You can use the default command as seen above (a ListViewUserCommand), or use a custom command by extending ListViewCommand and overriding the command methods.
Custom Command Example
In the custom command you have access to the Owner (RadListView), so you can call a method on the BindingContext as well as EndRefresh().
<
telerikDataControls:RadListView
BindingContext
=
"{StaticResource viewModel}"
ItemsSource
=
"{Binding Items}"
IsPullToRefreshEnabled
=
"True"
>
<
telerikDataControls:RadListView.Commands
>
<
portable:CustomRefreshRequestedCommand
/>
</
telerikDataControls:RadListView.Commands
>
</
telerikDataControls:RadListView
>
Command
public
class
CustomRefreshRequestedCommand : ListViewCommand
{
public
CustomRefreshRequestedCommand()
{
this
.Id = CommandId.PullToRefreshRequested;
}
public
override
bool
CanExecute(
object
parameter)
{
return
true
;
}
public
override
void
Execute(
object
parameter)
{
Device.BeginInvokeOnMainThread(() =>
{
(Owner?.BindingContext
as
ViewModel)?.RefreshItems();
Owner?.EndRefresh();
});
}
}
Documentation
The documentation and SDKExample examples still needs to be updated with these options. I have informed the development team so that they can make sure these are in the next updates.
In the meantime, the RadDataGrid does have a Commands article that is similar to explain what some of the properties are, but it's not an exact match (e.g. the IDs are different).
Further support
If you have any difficulty implementing a command, open a support ticket here and I'll make sure the approriate engineering team follows up with you.
Regards,
Lance | Tech Support Engineer, Sr.
Progress Telerik