我有一个异步事件处理程序,每当文本更改时,该事件处理程序就会在我的输入字段中触发。这是一个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服务时,我也发生了同样的异步“僵局”
我猜问题可能很相似?
答案 0 :(得分:0)
就像@JSteward一样,没有必要使用Task.Yield(),并且由于这是导致应用程序挂起的原因,因此现在可以解决此问题。可以在以下位置找到OnTextChanged处理程序的更新代码,该处理程序模拟改写模式以及如何通过Entry类的C#扩展轻松使用它: https://forums.xamarin.com/discussion/143533/is-it-possible-to-have-overtype-functionality-in-entry
我希望这会在将来对某人有所帮助:)