Асинхронный обработчик событий иногда зависает в Xamarin.Forms - PullRequest
0 голосов
/ 18 декабря 2018

У меня есть обработчик асинхронных событий, который запускается в моем поле ввода всякий раз, когда изменяется текст.Это приложение Xamarin.Forms, и я использую обработчик событий TextChanged для того, чтобы имитировать функциональность «сверхпечатного типа» в моей записи, например, для написания текста при вставке ключа в активный.Однако иногда это приводит к блокировке приложения после вызова await Task.Yield ().Этот вызов необходим для получения правильного поведения, в противном случае каретка не переходит в правильную позицию после выполнения вызова.Я не могу понять, почему код передает и как решить эту проблему, поэтому любая помощь / совет будут оценены.Я предполагаю, что проблема связана с моим недостаточным знанием асинхронного программирования.

private static async void OnOvertypeTextChanged(object sender, TextChangedEventArgs e)
{
        var guid = Guid.NewGuid();
        Debug.WriteLine($"{DateTime.Now.ToString()}: START {guid.ToString()}");
        var entry = sender as CustomEntry;
        if (entry.IsOvertypeRunning)
        {
            return;
        }
        else
        {
            entry.IsOvertypeRunning = true;
        }
        try
        {
            entry.TextChanged -= OnOvertypeTextChanged;
            //Update value as in overtype mode
            var oldVal = e.OldTextValue;
            var newVal = e.NewTextValue;
            int? carret = null;
            //If new string is longer, we should go into overtype mode, otherwise ignore it
            if (newVal?.Length > oldVal?.Length)
            {
                var i = entry.CursorPosition;
                var overtyped = oldVal.Substring(0, i) + newVal[i] + ((oldVal.Length > (i + 1)) ? oldVal.Substring(i + 1) : "");
                entry.Text = overtyped;
                carret = i + 1;
                //Check if new overtyped value is longer than max allowed size
                if (entry.OvertypeLength != -1 && entry.Text.Length > entry.OvertypeLength)
                {
                    var cut = entry.Text.Substring(0, entry.OvertypeLength);
                    //If new text would be longer, then cut it
                    entry.Text = cut;
                    if (carret >= cut.Length)
                    {
                        carret = cut.Length;
                    }
                }
            }
            //For some reason, this is needed...
            if (carret != null)
            {
                Debug.WriteLine($"{DateTime.Now.ToString()}: WAITING {guid.ToString()}");
                await Task.Yield();
                Debug.WriteLine($"{DateTime.Now.ToString()}: DONE_WAITING {guid.ToString()}");
                Debug.WriteLine($"{DateTime.Now.ToString()}: SETTING_CURSOR {guid.ToString()} @ {carret.Value.ToString()}");
                entry.CursorPosition = carret.Value;
                Debug.WriteLine($"{DateTime.Now.ToString()}: CURSOR_SET {guid.ToString()}");
            }
            Debug.WriteLine($"{DateTime.Now.ToString()}: DONE {guid.ToString()}");
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"{DateTime.Now.ToString()}: ERROR {guid.ToString()}", ex);
        }
        finally
        {
            entry.IsOvertypeRunning = false;
            entry.TextChanged += OnOvertypeTextChanged;
            Debug.WriteLine($"{DateTime.Now.ToString()}: END {guid.ToString()}");
        }
}

Так что произойдет, что все будет работать нормально, сразу после нескольких успешных событий фокусировки / расфокусировки в Entry,он будет зависать.

Таким образом, при регистрации будет что-то вроде:

[0:] 18. 12. 2018 17:57:26: START bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: WAITING bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: DONE_WAITING bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: SETTING_CURSOR bba4b754-8f22-4a14-ae28-8536d3a1e3d1 @ 14
[0:] 18. 12. 2018 17:57:26: CURSOR_SET bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: DONE bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: END bba4b754-8f22-4a14-ae28-8536d3a1e3d1
[0:] 18. 12. 2018 17:57:26: START 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: WAITING 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: DONE_WAITING 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: SETTING_CURSOR 71bf9809-6217-4d73-94df-817042a251b9 @ 14
[0:] 18. 12. 2018 17:57:26: CURSOR_SET 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: DONE 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:26: END 71bf9809-6217-4d73-94df-817042a251b9
[0:] 18. 12. 2018 17:57:31: START f9fca969-e141-4a07-968d-e32616323995
[0:] 18. 12. 2018 17:57:31: WAITING f9fca969-e141-4a07-968d-e32616323995

И после этого приложение перестает отвечать на запросы и отображает сообщение «Приложение X не отвечает ...»

При вызове сервисов HttpClient со мной происходили такие же асинхронные "тупики", как описано в CLICK

Я предполагаю, что проблемы могут быть похожими?

1 Ответ

0 голосов
/ 27 декабря 2018

Как и любезно отмечено @JSteward, использование Task.Yield () не является необходимым, и поскольку это было причиной зависания приложения, теперь это решено.Обновленный код для обработчика OnTextChanged, который имитирует режим overtype и как его легко использовать с расширениями C # для класса Entry, можно найти здесь: https://forums.xamarin.com/discussion/143533/is-it-possible-to-have-overtype-functionality-in-entry

Надеюсь, это поможет кому-то в будущем:)

...