【问题标题】:await DisplayActionSheet(…) return null immediately on Windows在 Windows 上等待 DisplayActionSheet(...) 立即返回 null
【发布时间】:2016-06-09 19:43:58
【问题描述】:

我需要显示来自 ViewModel 的 MessageDialog,并且我需要将 Action 与按下的按钮相关联。为此,我编写了以下内容:

//Dummy implementation
private string Translate(string element) => element;

public async Task ShowAsync(string message, Dictionary<string, Action> commands)
{
    var translatedCommands = new Dictionary<string, Action>();
    foreach (var element in commands)
        translatedCommands.Add(Translate(element.Key), element.Value);

    string selectedElement = null;

    var buttons = new string[translatedCommands.Keys.Count];
    translatedCommands.Keys.CopyTo(buttons, 0);

    Task<string> Result = null;
    Device.BeginInvokeOnMainThread(() =>
    {
        Result = App.Current.MainPage.DisplayActionSheet(message, null, null, buttons);
    });

    selectedElement = await Result;
    if (selectedElement == null)
        return;

    translatedCommands[selectedElement]?.Invoke();
}

然后我从 RelayCommand 调用它

   private async void ExecuteButtonCommand(object p)
        {
            int Selectedindex = 0;

            var messageCommands = new Dictionary<string, Action>()
            {
                {  "Before 2003", () =>
                    {
                        Selectedindex = 1;
                    }
                },
                {  "After 2003", () =>
                    {
                        Selectedindex = 2;
                    }
                },
            };

            await ShowAsync("Select period", messageCommands);
            var dummy = Selectedindex;
        }

这在 Android 上运行良好,但在 Windows 上 DisplayActionSheet 立即返回 null。我见过this so question,但它对我不起作用,因为如果我在Device.BeginInvokeOnMainThread 内部等待,ShowAsync 不会变成可等待的。

【问题讨论】:

    标签: c# android xamarin xamarin.android xamarin.forms


    【解决方案1】:

    我的猜测是,在 Android 上,BeginInvokeOnMainThread 中的 Action 会立即执行,并为 Result 分配一个值。在 Windows 上,Action 可能不会在调用 BeginInvokeOnMainThread 方法后立即执行。

    您真的不应该像您在这里所做的那样在另一个线程上执行结果相关操作。相反,您应该等待分配Result在主线程上执行ShowAsync 的后半部分。

    我推荐第二个选项,因为除了在主线程中分配 Result 之外,您实际上并没有做任何其他事情:

    Device.BeginInvokeOnMainThread(() =>
    {
        string selectedElement = await App.Current.MainPage.DisplayActionSheet(message, null, null, buttons);
        if (selectedElement == null)
            return;
    
        translatedCommands[selectedElement]?.Invoke();
    });
    

    然而,这不再使ShowAsync 异步了。要制作此方法的异步版本,只需将 ShowAsync 的编辑内容提取到同步的 Show 方法中,并创建一个异步包装器:

    private void Show(string message, Dictionary<string, Action> commands)
    {
        // Code in ShowAsync is moved here
    }
    
    public Task ShowAsync(string message, Dictionary<string, Action> commands)
    {
        return Task.Run(() => Show(message, commands));
    }
    

    【讨论】:

    • 不!它没有用。 Show 不会等到 messagedialog 关闭,并且 DisplayActionSheet 不会等待。所以我的动作没有被执行。
    【解决方案2】:

    如果找到解决方案。

    在 Windows(电话)上,DisplayActionSheet 不应在 MainThread 中执行,而应等待。

    public async Task ShowAsync(string message, Dictionary<string, Action> commands)
    {
        var translatedCommands = new Dictionary<string, Action>();
        foreach (var element in commands)
            translatedCommands.Add(Translate(element.Key), element.Value);
    
        var buttons = new string[translatedCommands.Keys.Count];
        translatedCommands.Keys.CopyTo(buttons, 0);
    
    
        string selectedElement = null;
    
        if (Device.OS == TargetPlatform.Android)
        {
            Task<string> Result = null;
            Device.BeginInvokeOnMainThread(() =>
            {
                Result = App.Current.MainPage.DisplayActionSheet(message, null, null, buttons);
            });
    
            selectedElement = await Result;
        }
        else if (Device.OS == TargetPlatform.Windows || Device.OS == TargetPlatform.WinPhone)
        {
            selectedElement = await App.Current.MainPage.DisplayActionSheet(message, null, null, buttons);
        }
        else
            throw new NotImplementedException("Only implemented for Android and Windows (Phone)");
    
        if (selectedElement == null)
            return;
    
        translatedCommands[selectedElement]?.Invoke();
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-22
      • 2013-05-01
      • 1970-01-01
      • 2013-11-02
      • 1970-01-01
      • 2020-02-15
      • 1970-01-01
      • 2010-12-17
      • 2023-02-14
      相关资源
      最近更新 更多