异步事件处理程序有时会挂在Xamarin.Forms

时间:2018-12-18 17:42:55

标签: c# asynchronous xamarin.forms async-await

我有一个异步事件处理程序,每当文本更改时,该事件处理程序就会在我的输入字段中触发。这是一个Xamarin.Forms应用程序,我使用事件处理程序TextChanged来模拟我的Entry中的“ over-type”功能,例如,在激活插入键时编写文本。但是,这有时会导致应用程序在等待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

在该应用程序无响应并显示消息“ Application X没有响应...”

在调用CLICK中所述的HttpClient服务时,我也发生了同样的异步“僵局”

我猜问题可能很相似?

1 个答案:

答案 0 :(得分:0)

就像@JSteward一样,没有必要使用Task.Yield(),并且由于这是导致应用程序挂起的原因,因此现在可以解决此问题。可以在以下位置找到OnTextChanged处理程序的更新代码,该处理程序模拟改写模式以及如何通过Entry类的C#扩展轻松使用它: https://forums.xamarin.com/discussion/143533/is-it-possible-to-have-overtype-functionality-in-entry

我希望这会在将来对某人有所帮助:)