Blazor Custom Longpress Button - убедиться, что действие запускает только один разC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Blazor Custom Longpress Button - убедиться, что действие запускает только один раз

Сообщение Anonymous »

У нас есть Blazor Web UI с компонентами Mudblazor, работающий на киосковом ПК с TouchScren. Проблема заключается в том, что наши пользователи часто ставят пальцем на кнопку и просто держите их там. Таким образом, событие Onclick не стреляет, так что ничего не происходит. Затем они жалуются на то, что наш киоск не работает. /> [*] Нормальная кнопка нажатия по -прежнему работает < /li>
< /ul>
Как я ее реализовал:
on ontouchstart Начался таймер 300 мс (или задача. Остановлен < /li>
Проверяется «_ActionExecated». Если это ложь, это немедленно установлено на TRUE, и действие выполняется. Если это уже правда, ничего не происходит, я просто возвращаюсь. < /Li>
< /ul>
Это кажется довольно простым, но даже при проверке действие иногда запускается дважды.@inherits MudButton


@ChildContent

< /code>
private async Task ExecuteAction(bool fromTimer)
{
string origin = fromTimer ? "timer" : "touch end";
if (_actionExecuted)
{
Console.WriteLine($" KioskButton - {origin} - {DataTestId} - action tried to double-fire.");
return;
}// Prevent multiple calls
_actionExecuted = true;

Console.WriteLine($"a) KioskButton - {origin} - {DataTestId} - action triggered and passed check.");

if (OnAction != null)
{
Console.WriteLine($"b) KioskButton - {origin} - {DataTestId} - performing OnAction.");
await OnAction(Parameters);
}
}

private void StartTimer()
{
StopTimer(); // Ensure no previous timer is running
_actionExecuted = false;
_cts = new CancellationTokenSource();

Task.Delay(HoldDuration, _cts.Token).ContinueWith(async t =>
{
if (!t.IsCanceled)
{
await ExecuteAction(true);
}
}, TaskScheduler.Default);
}

private async Task HandleRelease()
{
StopTimer(); // Stop the hold timer
await ExecuteAction(false); // Execute if not already triggered
}

private void StopTimer()
{
_cts?.Cancel();
_cts?.Dispose();
_cts = null;
}
< /code>
I was under the impression this code should have prevented double-firing of the action. But it does happen, actually quite often - maybe one out of 5 clicks (although when I try to reproduce it on purpose, it stops happening). Is there a way to make absolutely sure the button never double-fires?
Edit:
This is in response to MrC aka Shaun Curtis.
Thanks again for your help.
Yes, there is more I wasn't showing. I didn't want to describe the full extent of what I'm trying to do, as I would likely get knocked for "asking more than one question" and "trying to get people to do my work for me". So I boiled it down to the logic that I naively believed was the only problem and posted that. Then I integrated your logic instead of mine. It helped, but then other issues cropped up. I will post the full problem below.
But first, I seem to have figured out the double-firing issue. I put in the 2-second delay, followed by NavigationManager.NavigateTo(). I observed something strange:
On the first try after deploying the app, I tapped the button, it went grey for two seconds, then it got enabled again, and a moment after that navigation to the next page happened. On second try the navigation happened a lot faster and I didn't observe this inconsistency.
It seems that when I call NavigationManager.NavigateTo(), it triggers a parallel process that consists of loading the new page and then navigating to it. But NavigationManager.NavigateTo() is not async, it can't be awaited, so my code just continues running. The action executes, the button becomes available, and if the user still has their finger on it, it gets triggered. (on the second try the next page is already cached, so the whole navigation happens much faster and there isn't time for this to happen). Knowing this I managed to solve the double-fire issue by adding a simple rule:

If you're going to navigate to another page, don't re-enable the
button.


Here's my full scope:
I'm making a button component, that ideally should replace MudButton as seamlessly as possible. I'm using it like so:
// button with action
Do The Thing

//button with link
Go to next page

// definition of OnAction and Parameters
[Parameter] public Func? OnAction { get; set; }

[Parameter] public object[] Parameters { get; set; } = Array.Empty();

< /code>
The button takes the function to execute as parameter, and also needs to work with the Disabled parameter - i.e. it can be disabled based on external conditions, not just when its action is being executed.
Crucially, the buttons need to work everywhere, including dialogs. This brings me to the issues I've been having:
  • Those damn dialogs
We're using MudDialog instances for our dialogs. I've replaced the buttons in the dialog template with KioskButtons. I've added a parameter for the dialog:
[Parameter] public Action? OnActionVoid { get; set; }
< /code>
because for MudDialog you need to call these void methods:
void Submit() => MudDialog.Close(DialogResult.Ok(true));
void Cancel() => MudDialog.Cancel();
< /code>
However I've learned there is a threading issue, as I need to call the method like this:
if (OnActionVoid != null)
{
await InvokeAsync(() =>
{
Console.WriteLine($"b) KioskButton - {DataTestId} - performing OnActionVoid - {origin}");
OnActionVoid(Parameters);
StateHasChanged();
});
}
< /code>
Otherwise the dialog stays open when the button is clicked. However this seems to be causing the dispatcher issue. Though it seems to be only in conjunction with the button functionality - Button A triggers a dialog, Button B on the dialog closes it using IvokeAsync, and then there's an attempt to update the state of Button A, and the exception occurs.
  • a)
There's an interesting sub-problem. I have a screen with a text input and a button. When the button is pressed, it performs a search based on the input, and either shows a dialog or navigates to another page based on the result. When I select the text input, an on-screen keyboard called Squeekboard pops up. This is a "system" keyboard, completely outside the browser. In fact it resizes the browser window so it can fit underneath it. But here's the fun part: if I just tap on the button, the keyboard disappears, the browser resizes back, and then the dialog is shown. But if I do the longpress, the keyboard remains and the dialog is shown - shifted up as everything is resized. I assumed the text input doesn't get de-focused properly, so I tried to do this manually. Blazor components don't have a "Blur" method, so I tried focusing the button instead.
if (_submitButton != null)
{
await _submitButton.FocusAsync();
StateHasChanged();
}
< /code>
This caused the dialog to not show up. I've tried a few things, results ranged from not working to throwing exceptions.
  • Disabling the button
On the aforementioned screen, if the input box is empty, the button should be disabled. But your solution uses the Disabled parameter for disabling the button during execution. I've tried to somehow combine the logic, but I'm getting inconsistent behavior.
First of all, Blazor won't allow me to define the Disabled parameter on my own component and hide the one its base MudButton. So I've been trying to combine the values on OnParametersSet, and then refresh before and after execution. But the Disabled value from outside can change over time, so it's inconsistent. Though I suppose I can solve this by creating a custom IsDisabled parameter.

Подробнее здесь: https://stackoverflow.com/questions/795 ... ggers-once
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Blazor Custom Longpress Button - убедиться, что действие запускает только один раз
    Anonymous » » в форуме C#
    0 Ответы
    8 Просмотры
    Последнее сообщение Anonymous
  • Blazor Custom Longpress Button - убедиться, что действие запускает только один раз
    Anonymous » » в форуме C#
    0 Ответы
    2 Просмотры
    Последнее сообщение Anonymous
  • Blazor Custom Longpress Button - убедиться, что действие запускает только один раз
    Anonymous » » в форуме C#
    0 Ответы
    4 Просмотры
    Последнее сообщение Anonymous
  • Blazor Custom Long нажмите кнопку - убедиться, что действие только запускает один
    Anonymous » » в форуме C#
    0 Ответы
    4 Просмотры
    Последнее сообщение Anonymous
  • Blazor Custom Long нажмите кнопку - убедиться, что действие только запускает один
    Anonymous » » в форуме C#
    0 Ответы
    3 Просмотры
    Последнее сообщение Anonymous

Вернуться в «C#»