-
Notifications
You must be signed in to change notification settings - Fork 2k
[Windows] Fix RefreshView IsRefreshing property not working while binding #34845
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1b144a4
668a3bf
9a724db
e364027
5c0b0eb
200aa16
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,192 @@ | ||
| using System.ComponentModel; | ||
| using System.Runtime.CompilerServices; | ||
|
|
||
| namespace Maui.Controls.Sample.Issues; | ||
|
|
||
| [Issue(IssueTracker.Github, 30535, "[Windows] RefreshView IsRefreshing property not working while binding", PlatformAffected.All)] | ||
| public class Issue30535 : NavigationPage | ||
| { | ||
| public Issue30535() | ||
| : base(new Issue30535MainPage()) | ||
| { | ||
| } | ||
| } | ||
|
|
||
| class Issue30535MainPage : ContentPage | ||
| { | ||
| Issue30535MainViewModel _viewModel; | ||
|
|
||
| public Issue30535MainPage() | ||
| : this(new Issue30535MainViewModel()) | ||
| { | ||
| } | ||
|
|
||
| public Issue30535MainPage(Issue30535MainViewModel viewModel) | ||
| { | ||
| _viewModel = viewModel; | ||
| BindingContext = _viewModel; | ||
| Title = "Main"; | ||
|
|
||
| var optionsToolbarItem = new ToolbarItem | ||
| { | ||
| Text = "Options", | ||
| AutomationId = "Options" | ||
| }; | ||
| optionsToolbarItem.Clicked += OnNavigateToControlPageClicked; | ||
| ToolbarItems.Add(optionsToolbarItem); | ||
|
|
||
| var infoLabel = new Label | ||
| { | ||
| Text = "Pull down to refresh this content", | ||
| FontSize = 18, | ||
| HorizontalOptions = LayoutOptions.Center | ||
| }; | ||
|
|
||
| var isRefreshingLabel = new Label | ||
| { | ||
| FontSize = 16, | ||
| HorizontalOptions = LayoutOptions.Center, | ||
| TextColor = Colors.Blue | ||
| }; | ||
| isRefreshingLabel.SetBinding(Label.TextProperty, new Binding(nameof(Issue30535MainViewModel.IsRefreshing), stringFormat: "IsRefreshing: {0}")); | ||
|
|
||
| var boxContent = new BoxView | ||
| { | ||
| Color = Colors.Green, | ||
| HeightRequest = 100, | ||
| WidthRequest = 200, | ||
| HorizontalOptions = LayoutOptions.Center, | ||
| AutomationId = "BoxContent" | ||
| }; | ||
|
|
||
| var stackLayout = new StackLayout | ||
| { | ||
| Spacing = 20, | ||
| Padding = 20, | ||
| Children = | ||
| { | ||
| infoLabel, | ||
| isRefreshingLabel, | ||
| boxContent, | ||
| } | ||
| }; | ||
|
|
||
| var scrollView = new ScrollView | ||
| { | ||
| Content = stackLayout | ||
| }; | ||
|
|
||
| var refreshView = new RefreshView | ||
| { | ||
| Content = scrollView, | ||
| RefreshColor = Colors.Red | ||
| }; | ||
| refreshView.SetBinding(RefreshView.IsRefreshingProperty, nameof(Issue30535MainViewModel.IsRefreshing), mode: BindingMode.TwoWay); | ||
|
|
||
| Content = refreshView; | ||
| } | ||
|
|
||
| async void OnNavigateToControlPageClicked(object sender, EventArgs e) | ||
| { | ||
| BindingContext = _viewModel = new Issue30535MainViewModel(); | ||
| await Navigation.PushAsync(new RefreshControlPage(_viewModel)); | ||
| } | ||
| } | ||
|
|
||
| public class RefreshControlPage : ContentPage | ||
| { | ||
| readonly Issue30535MainViewModel _viewModel; | ||
|
|
||
| public RefreshControlPage(Issue30535MainViewModel viewModel) | ||
| { | ||
| _viewModel = viewModel; | ||
| BindingContext = _viewModel; | ||
| Title = "Options"; | ||
|
|
||
| var applyToolbarItem = new ToolbarItem | ||
| { | ||
| Text = "Apply", | ||
| AutomationId = "Apply" | ||
| }; | ||
| applyToolbarItem.Clicked += OnBackClicked; | ||
| ToolbarItems.Add(applyToolbarItem); | ||
|
|
||
| var currentValueLabel = new Label | ||
| { | ||
| FontSize = 18, | ||
| HorizontalOptions = LayoutOptions.Center, | ||
| TextColor = Colors.Blue | ||
| }; | ||
| currentValueLabel.SetBinding(Label.TextProperty, new Binding(nameof(Issue30535MainViewModel.IsRefreshing), mode: BindingMode.TwoWay, stringFormat: "Current IsRefreshing: {0}")); | ||
|
|
||
| var setTrueButton = new Button | ||
| { | ||
| Text = "Set IsRefreshing = True", | ||
| BackgroundColor = Colors.Green, | ||
| AutomationId = "SetIsRefreshingTrue", | ||
| TextColor = Colors.White | ||
| }; | ||
| setTrueButton.Clicked += OnSetTrueClicked; | ||
|
|
||
| var setFalseButton = new Button | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Suggestion — The "Set IsRefreshing = False" button is key to the two-way binding scenario (resetting the refresh state from a bound property), but without an var setFalseButton = new Button
{
Text = "Set IsRefreshing = False",
AutomationId = "SetIsRefreshingFalse",
BackgroundColor = Colors.Red,
TextColor = Colors.White
}; |
||
| { | ||
| Text = "Set IsRefreshing = False", | ||
| BackgroundColor = Colors.Red, | ||
| TextColor = Colors.White | ||
| }; | ||
| setFalseButton.Clicked += OnSetFalseClicked; | ||
|
|
||
| Content = new VerticalStackLayout | ||
| { | ||
| Spacing = 20, | ||
| Padding = 20, | ||
| VerticalOptions = LayoutOptions.Center, | ||
| Children = | ||
| { | ||
| currentValueLabel, | ||
| setTrueButton, | ||
| setFalseButton | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| void OnSetTrueClicked(object sender, EventArgs e) | ||
| { | ||
| _viewModel.IsRefreshing = true; | ||
| } | ||
|
|
||
| void OnSetFalseClicked(object sender, EventArgs e) | ||
| { | ||
| _viewModel.IsRefreshing = false; | ||
| } | ||
|
|
||
| async void OnBackClicked(object sender, EventArgs e) | ||
| { | ||
| await Navigation.PopAsync(); | ||
| } | ||
| } | ||
|
|
||
| public class Issue30535MainViewModel : INotifyPropertyChanged | ||
| { | ||
| bool _isRefreshing; | ||
|
|
||
| public bool IsRefreshing | ||
| { | ||
| get => _isRefreshing; | ||
| set | ||
| { | ||
| if (_isRefreshing == value) | ||
| return; | ||
|
|
||
| _isRefreshing = value; | ||
| OnPropertyChanged(); | ||
| } | ||
| } | ||
|
|
||
| public event PropertyChangedEventHandler PropertyChanged; | ||
|
|
||
| protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) | ||
| { | ||
| PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| using NUnit.Framework; | ||
| using UITest.Appium; | ||
| using UITest.Core; | ||
|
|
||
| namespace Microsoft.Maui.TestCases.Tests.Issues; | ||
|
|
||
| public class Issue30535 : _IssuesUITest | ||
| { | ||
| public override string Issue => "[Windows] RefreshView IsRefreshing property not working while binding"; | ||
|
|
||
| public Issue30535(TestDevice device) : base(device) | ||
| { | ||
| } | ||
|
|
||
| [Test] | ||
| [Category(UITestCategories.RefreshView)] | ||
| public void RefreshViewSetIsRefreshingValueinNewPageAndVerifyStatus() | ||
| { | ||
|
devanathan-vaithiyanathan marked this conversation as resolved.
|
||
| App.WaitForElement("Options"); | ||
| App.Tap("Options"); | ||
| App.WaitForElement("SetIsRefreshingTrue"); | ||
| App.Tap("SetIsRefreshingTrue"); | ||
| App.WaitForElement("Apply"); | ||
| App.Tap("Apply"); | ||
| VerifyScreenshot(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Add a wait for a stable main-page element: App.Tap("Apply");
App.WaitForElement("BoxContent"); // wait for main page fully loaded
VerifyScreenshot();Or use the retry overload: VerifyScreenshot(retryDelay: TimeSpan.FromSeconds(2)); |
||
| } | ||
|
devanathan-vaithiyanathan marked this conversation as resolved.
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Suggestion —
PlatformAffected.Alloverstates the fix scopeThe only modified production file is
RefreshViewHandler.Windows.cs. The[Issue]attribute would be more accurate asPlatformAffected.UWP(the closest Windows-targeted value in the enum). This is metadata-only and does not affect test execution, but helps future triage correctly identify the platform scope: