提问人:Zerachiel 提问时间:11/7/2023 更新时间:11/8/2023 访问量:64
如何防止处理多个 GestureRecognizers.Tapped 事件
How to prevent multiple GestureRecognizers.Tapped events from being handled
问:
所以我有这个 MAUI 应用程序,它允许用户在边框内点击以加载一些数据并打开另一个 ContentPage。为了处理用户的点击,我在边框中添加了一个 GestureRecognizer,如下所示:
<Border>
<Border.GestureRecognizers>
<TapGestureRecognizer Tapped="HandleBorderTapped"/>
</Border.GestureRecognizers>
</Border>
该方法如下所示:HandleBorderTapped
private async void HandleBorderTapped(object sender, TappedEventArgs e)
{
await LoadSomeDataAsync().ConfigureAwait(true);
await Shell.Current.GoToAsync("Another ContentPage").ConfigureAwait(true);
}
现在,该方法需要几秒钟的时间,不耐烦的用户可能会在边框内多次点击。不幸的是,这会导致应用程序多次打开 ContentPage,从而导致包含许多 ContentPage 的导航堆栈。这是我想避免的。LoadSomeDataAsync
我尝试通过添加这样的布尔值来阻止第二次点击处理:
private volatile bool isLoading;
private async void HandleBorderTapped(object sender, TappedEventArgs e)
{
if (isLoading)
return;
isLoading = true;
await LoadSomeDataAsync().ConfigureAwait(true);
await Shell.Current.GoToAsync("Another ContentPage").ConfigureAwait(true);
isLoading = false;
}
这种帮助,但并不能完全解决我的问题。现在,如果我点击 5 次,ContentPage 只会打开两次,而不是 5 次。不过,ContentPage 应该只打开一次......
谁能告诉我如何防止 GestureRecognizer 识别多个点击?或者如何限制我的 -method 或类似的东西中的并发线程?HandleBorderTapped
提前致谢!
答:
可以使用 NumberOfTapsRequired 属性,如下所示。
<Border>
<Border.GestureRecognizers>
<TapGestureRecognizer
Tapped="HandleBorderTapped"
NumberOfTapsRequired="1"/>
</Border.GestureRecognizers>
</Border>
评论
此答案显示了如何防止处理多个 GestureRecognizers.Tapped 事件,并提供了一个最小示例,即锁定 .NET Maui 默认应用程序上的 [单击我] 按钮,直到最后一次单击后的某个间隔(在本例中为 2 秒)。对于可重新启动的时间间隔,需要某种看门狗定时器。可以使用以下说明将合适计时器的 NuGet 添加到项目中。该解决方案的第二个元素是具有覆盖整个屏幕的覆盖框架。
通常,属性是 ,并且覆盖不会干扰点击。点击五次,你会得到五。IsVisible
false
当叠加层可见时,外观设置为 并在启用时为屏幕提供“禁用”外观。该 可防止 [Click Me] 按钮识别点击,但仅当 overly 设置为 时。BackgroundColor="DarkGray"
Opacity="0.25"
InputTransparent="False"
IsVisible
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="lock_out_tap_overlay.MainPage">
<Grid>
<ScrollView>
<VerticalStackLayout
Spacing="25"
Padding="30,0"
VerticalOptions="Center">
<Image
Source="dotnet_bot.png"
SemanticProperties.Description="Cute dot net bot waving hi to you!"
HeightRequest="200"
HorizontalOptions="Center" />
<Label
Text="Hello, World!"
SemanticProperties.HeadingLevel="Level1"
FontSize="32"
HorizontalOptions="Center" />
<Label
Text="Welcome to .NET Multi-platform App UI"
SemanticProperties.HeadingLevel="Level2"
SemanticProperties.Description="Welcome to dot net Multi platform App U I"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="Click me"
SemanticProperties.Hint="Counts the number of times you click"
Clicked="OnCounterClicked"
HorizontalOptions="Center" />
<HorizontalStackLayout HorizontalOptions="Center">
<CheckBox
x:Name="checkboxIsLockOutMechanismEnabled"
IsChecked="False"
Margin="10"
HorizontalOptions="Start"
VerticalOptions="Center"/>
<Label
Text="Enable Lock Out Mechanism"
VerticalTextAlignment="Center"
HorizontalOptions="Start" />
</HorizontalStackLayout>
</VerticalStackLayout>
</ScrollView>
<~--Overlay-->
<Frame
BackgroundColor="DarkGray"
Opacity="0.25"
InputTransparent="False"
IsVisible="{Binding IsLockedOut}">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="OnOverlayTapped"/>
</Frame.GestureRecognizers>
</Frame>
</Grid>
</ContentPage>
C#
我们用于将此属性挂接到看门狗计时器。{Binding IsLockedOut}
public partial class MainPage : ContentPage
{
int count = 0;
public MainPage()
{
BindingContext = this;
InitializeComponent();
}
private void OnCounterClicked(object sender, EventArgs e)
{
if (checkboxIsLockOutMechanismEnabled.IsChecked)
{
ExtendLockout();
}
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
}
WatchdogTimer _wdtOverlay = new WatchdogTimer();
private void ExtendLockout()
{
_wdtOverlay.StartOrRestart(
initialAction: () => IsLockedOut = true,
completeAction: () => IsLockedOut = false);
}
public bool IsLockedOut
{
get => _isLockedOut;
set
{
if (!Equals(_isLockedOut, value))
{
_isLockedOut = value;
OnPropertyChanged();
}
}
}
bool _isLockedOut = false;
private void OnOverlayTapped(object sender, TappedEventArgs e)
{
ExtendLockout();
}
}
结果是,从上次点击屏幕开始,UI 将在两秒钟内没有响应。需要明确的是,如果你坐下来每秒点击一次屏幕,你将永远“永远不会”看到第二次点击。
将 WatchdogTimer 添加到项目
有多种方法可以制作看门狗定时器。这是我测试这个答案的那个。
评论