【问题标题】:Xamarin Forms keyboard remaining even Editor is not visible (How to wait other task thread to complete? )Xamarin Forms 键盘仍然存在,即使编辑器不可见(如何等待其他任务线程完成?)
【发布时间】:2020-08-26 07:44:21
【问题描述】:

Github repository 重现问题。

我正在使用 Xamarin Forms 来创建应用程序。

<StackLayout>
    <Editor x:Name="Editor"
            Text="{Binding Text, Mode=TwoWay}">
    </Editor>
    <Button x:Name="Button"
            Text="Complete"
            Command="{Binding CompleteCommand}" />
</StackLayout>

ContentView 可见时,我试图将焦点锁定在Editor

因此,我使用Editor.Unfocused 事件来锁定焦点,如下所示。

public partial class MyView : ContentView
{
    private void OnEditorUnfocused(object sender, FocusEventArgs e)
    {
        if (IsVisible)
        {
            Editor.Focus();
        }
    }
}

ContentView.IsVisible 属性发生如下变化时,我注册和注销OnEditorUnfocused 方法。

public partial class MyView : ContentView
{
    protected override void OnPropertyChanging([CallerMemberName] string propertyName = null)
    {
        // IsVisible changes from "True" to "False"
        if (propertyName.Equals("IsVisible") && IsVisible)
        {
            Editor.Unfocused -= OnEditorUnfocused;
            Editor.Unfocus();
        }

        base.OnPropertyChanging(propertyName);
    }

    protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        // IsVisible changed from "False" to "True"
        if (propertyName.Equals("IsVisible") && IsVisible)
        {
            Editor.Unfocused += OnEditorUnfocused;
            Editor.Focus();
        }

        base.OnPropertyChanged(propertyName);
    }
}

在这里我遇到了一个问题。 Editor.Focus()Editor.Unfocus() 不会立即应用。而当ContentView 不可见时,首先Editor.Focus() 不起作用。此外,当ContentView.VisibleButtonTrue 更改为False 时,键盘仍保留在屏幕上。

因此我像下面这样更改我的代码,

public partial class MyView : ContentView
{
        private Task _focusEditorTask;
        private Task _unfocusEditorTask;

        public event EventHandler LostFocused;

        public MyView()
        {
            InitializeComponent();

            _focusEditorTask = _unfocusEditorTask = Task.CompletedTask;
        }

        private void OnEditorUnfocused(object sender, FocusEventArgs e)
        {
            if (IsVisible)
            {
                FocusEditor();
                Console.WriteLine($"<Unfocused> Editor: Focused {Editor.IsFocused}");
            }
        }

        private void FocusEditor()
        {
            _unfocusEditorTask.Wait();
            _focusEditorTask.Wait();

            _focusEditorTask = Task.Factory.StartNew(async () =>
            {
                Console.WriteLine($"<FocusEditor> START {Editor.IsFocused}");

                while (!Editor.IsFocused)
                {
                    Editor.Focus();
                    await Task.Delay(100);
                    Console.WriteLine($"<FocusEditor> PROGRESS {Editor.IsFocused}");
                }
                Console.WriteLine($"<FocusEditor> END {Editor.IsFocused}");
            });
        }

        private void UnfocusEditor()
        {
            _focusEditorTask.Wait();
            _unfocusEditorTask.Wait();

            _unfocusEditorTask = Task.Factory.StartNew(async () =>
            {
                Console.WriteLine($"<!UnfocusEditor> START {Editor.IsFocused}");
                while (Editor.IsFocused)
                {
                    Editor.Unfocus();
                    await Task.Delay(100);
                    Console.WriteLine($"<!UnfocusEditor> PROGRESS {Editor.IsFocused}");
                }

                Console.WriteLine($"<!UnfocusEditor> END {Editor.IsFocused}");

                return Task.CompletedTask;
            });
        }

        protected override void OnPropertyChanging([CallerMemberName] string propertyName = null)
        {
            if (propertyName.Equals("IsVisible") && IsVisible)
            {
                Console.WriteLine($"<IsVisibleChanging> InputView: IsVisible ({IsVisible}) -> {!IsVisible}");
                Editor.Unfocused -= OnEditorUnfocused;
                UnfocusEditor();
            }

            base.OnPropertyChanging(propertyName);
        }

        protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            if (propertyName.Equals("IsVisible") && IsVisible)
            {
                Console.WriteLine($"<IsVisibleChanged> InputView: IsVisible {!IsVisible} -> ({IsVisible})");
                Editor.Unfocused += OnEditorUnfocused;
                FocusEditor();
            }

            base.OnPropertyChanged(propertyName);
        }
}

现在我只有一个问题,Wait() 无效。

这里是应用程序输出取决于ContnetView.IsVisible的变化,

1。将 ContnetView.IsVisiblefalse 更改为 true

    <IsVisibleChanged> InputView: IsVisible False -> (True)
    <FocusTextEditor> START False
    <FocusTextEditor> PROGRESS False
    <FocusTextEditor> PROGRESS True
    <FocusTextEditor> END True

2。 ButtonContentView.IsVisibletrue 更改为 false

    <Unfocused> TextEditor: Focused False
    <FocusTextEditor> START False
    <IsVisibleChanging> InputView: IsVisible (True) -> False
    // START should not fire...
    <!UnfocusTextEditor> START False
    <!UnfocusTextEditor> END False
    // because of this, keyboard does not disappear even ContnetView is not visible.
    <FocusTextEditor> PROGRESS True
    <FocusTextEditor> END True

【问题讨论】:

  • Editor.Unfocus() - 如果您将注意力集中在其他控件上会怎样?
  • @aepot 不幸的是我已经尝试过了。聚焦Button 不起作用。

标签: c# .net multithreading xamarin xamarin.forms


【解决方案1】:
  1. Task.Factory.StartNew()not awaitable this way。因为它在这里返回Task&lt;Task&gt;,而不是Task,然后必须等待内部Task。但是您可以简单地将其更改为Task.Run() 并完全修复它。最后,您在这里不需要线程。无需调用Task.Run(),只需使用异步调用即可完成这项工作。

  2. 您正在与池线程中的 UI 进行交互,这不好。

  3. 您使用.Wait() 锁定 UI 线程,这是一种不好的做法,在某些情况下可能会冻结 UI 或导致死锁。

  4. 您可以订阅一次活动。

我不熟悉 Xamarin,但很了解 Asynchronous Programming

这是我重写代码的尝试。

public partial class MyView : ContentView
{
    public MyView()
    {
        InitializeComponent();
    }

    private void OnEditorUnfocused(object sender, FocusEventArgs e)
    {
        if (Editor.IsVisible)
        {
            Editor.Focus();
            Console.WriteLine($"<Unfocused> Editor: Focused {Editor.IsFocused}");
        }
    }

    protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        base.OnPropertyChanged(propertyName);
        if (propertyName == nameof(IsVisible))
        {
            if (IsVisible)
            {
                Editor.Focus();
                Editor.Unfocused += OnEditorUnfocused;
            }
            else
            {
                Editor.Unfocused -= OnEditorUnfocused;
                Editor.Unfocus();
            }
            Console.WriteLine($"<IsVisibleChanged> InputView: IsVisible {!IsVisible} -> ({IsVisible})");
        }
    }
}

【讨论】:

  • 我将您的解决方案应用于复制代码并在FocusEditorAsync() 上无限等待它一定是由while 循环引起的。 Editor.IsFocused 不变! Applied Code on Github 我认为它不仅与异步编程有关...好伤心..
  • @ibocon 也许this 可以作为初始关注点。
  • 您提供的答案,Setting the Focus to an Entry in Xamarin.Forms,仅在出现Page 时有效。我所做的是在单击按钮时更改Visible。初始VisibleFalse。同样OnAppearing()方法在ContentView中不存在
  • @ibocon 也许检查Editor.IsVisible而不是View的IsVisible?更新了答案。
  • @ibocon Github 上的应用代码你忘了更新 OnPropertyChangingOnPropertyChanged 那里。顺便说一句,您可以完全删除这些方法。由于.Wait() 不允许在那里,可能无限await 导致那里出现死锁。如我所示,将事件订阅移动到构造函数。
猜你喜欢
  • 1970-01-01
  • 2013-05-26
  • 2020-09-21
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多