Skip to content

Proposal: Add IsRefreshEnabled Property and Platform-Consistent IsEnabled Semantics to RefreshView #30690

@mattleibow

Description

@mattleibow

Background & Use Case

Currently, disabling the RefreshView via IsEnabled=false disables not only the pull-to-refresh gesture but also all child controls within the RefreshView. This behavior is inconsistent across platforms (Android vs iOS) and differs from Xamarin.Forms, where only the refresh gesture was impacted. In Blazor Hybrid apps on Android, for example, disabling RefreshView disables all input on the login screen, making the app unusable (see linked issues below).

Users routinely have scenarios—such as login screens, loading spinners, or certain workflow states—where they want to temporarily disable pull-to-refresh but keep the contents of the view interactive.

Pain Points

  • Setting IsEnabled=false disables the entire UI subtree, not just the pull-to-refresh.
  • iOS and Android behave differently: iOS disables only pull-to-refresh, Android disables all children (breaking forms, buttons, etc).
  • Developers migrating from Xamarin.Forms expect to be able to disable only the gesture, not their content.
  • This creates blocking issues for Blazor Hybrid, MAUI, and any complex interactive screens.
  • Workarounds (such as conditionally wrapping/unwrapping RefreshView, or custom renderers/handlers) are clunky, error-prone, or not possible for all users.
  • Critically, the current implementation disables WebViews and HybridWebViews on Android, which is not intended and must be fixed.

Platform-Specific Behavior

The current IsEnabled and RefreshView behavior varies by platform:

Platform Current Observed Behavior Notes / Issue References
Android Disables gesture and all child controls (including WebViews/HybridWebViews) #29901, #19091
iOS Disables only pull-to-refresh gesture; children remain interactive #29901, #22699
Mac Catalyst Not specifically documented; likely follows iOS (disables gesture only, children interactive). Needs confirmation and alignment.
Windows Refresh indicator or RefreshView can block input in some scenarios (esp. with BlazorWebView); IsEnabled-specific inconsistencies not widely reported, but at least one issue highlights interaction problems #19715

Community Feedback & Discussion

Proposed Solution

1. Add IsRefreshEnabled for Granular Control

Introduce a new property on RefreshView:

public bool IsRefreshEnabled { get; set; }

Behavior:

  • When IsRefreshEnabled = false: The pull-to-refresh gesture is disabled, and the refresh indicator cannot be triggered by user interaction. All child controls remain interactive and enabled.
  • When IsRefreshEnabled = true: The pull-to-refresh gesture works as normal, and child controls are unaffected.

Benefits:

  • Developers gain granular, explicit control over gesture enablement, separate from general view interactivity.
  • Parity with Xamarin.Forms' typical usage patterns and user expectations.
  • Consistent behavior across platforms (Android, iOS, Windows, Mac Catalyst).
  • No breaking change—existing IsEnabled semantics are preserved.
  • Makes Blazor Hybrid and other MAUI scenarios much more robust and user-friendly.

2. Make IsEnabled Consistent Across All Platforms

Current Behavior by Platform

  • Android: Setting IsEnabled=false disables the RefreshView and all its child controls (including WebViews/HybridWebViews).
  • iOS: Setting IsEnabled=false disables only the pull-to-refresh gesture; child controls remain enabled and interactive.
  • Mac Catalyst: Not specifically documented; likely mirrors iOS behavior but needs confirmation.
  • Windows: Some issues with input blocking when RefreshView or refresh indicator is present; IsEnabled may not consistently disable all children in all cases.

Proposed Change

  • Make IsEnabled=false disable the entire RefreshView subtree (including all child controls), consistent with standard .NET and MAUI control semantics.
  • All platforms (Android, iOS, Mac Catalyst, Windows) should match this behavior.
  • This update will require changes to iOS, Mac Catalyst, and possibly Windows so that disabling the RefreshView also disables all child controls, matching Android’s behavior.

Rationale:

  • Aligns RefreshView’s IsEnabled property with the expectations for standard .NET UI controls.
  • Ensures predictable, cross-platform behavior for all MAUI users.
  • Avoids confusion and platform-specific code.

Note: The addition of IsRefreshEnabled allows developers to disable only the gesture while keeping the content interactive, so this change to IsEnabled does not remove any flexibility.

3. IsEnabled, IsRefreshEnabled, and Command.CanExecute Interconnection

In .NET MAUI and Xamarin.Forms, IsEnabled is commonly connected to Command.CanExecute for interactive controls. When a control is bound to a Command, changes to CanExecute will update IsEnabled accordingly. For consistency and developer clarity, RefreshView should maintain or strengthen this connection:

  • If a Command is assigned to RefreshView, its CanExecute state should affect the gesture enablement.
  • When CanExecute is false, both IsRefreshEnabled and the gesture should be disabled (and potentially IsEnabled as well, if appropriate).
  • Setting IsRefreshEnabled = false should also update the state of the gesture in a way that is consistent with how IsEnabled and CanExecute interact on other controls.
  • All three properties (IsEnabled, IsRefreshEnabled, and Command.CanExecute) should work together, so that disabling any of them results in the gesture being disabled and the intended user experience.

This ensures a seamless and predictable developer experience, especially for MVVM scenarios where command logic drives control state.

Example Usage

<RefreshView IsRefreshEnabled="false">
    <!-- All child controls are still enabled and interactive -->
    <BlazorWebView ... />
</RefreshView>

<RefreshView IsEnabled="false">
    <!-- All child controls, including BlazorWebView, are disabled -->
    <BlazorWebView ... />
</RefreshView>

Migration Guidance

  • Existing projects using IsEnabled for gesture control can migrate to IsRefreshEnabled for more precise behavior, and preserve child interactivity.
  • Projects that rely on disabling the entire RefreshView and its children should continue using IsEnabled=false and will now have consistent behavior across all supported platforms.
  • Developers leveraging Command.CanExecute for enabling/disabling gesture behavior should find the new interconnection with IsRefreshEnabled and IsEnabled to be consistent and predictable.

Related Issues

Metadata

Metadata

Type

No type

Projects

Status

Done

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions