简体   繁体   English

从 Func 返回真/假值<object, bool>使用 Android AlertDialog 实现,不会阻塞 UI</object,>

[英]Returning a true/false value from a Func<object, bool> implementation with an Android AlertDialog, without blocking the UI

I have to use a function in my Xamarin project, which has a DoOperation(Func<object, bool> ConfirmOperation) overload.我必须在我的 Xamarin 项目中使用 function,它有一个DoOperation(Func<object, bool> ConfirmOperation)重载。 The object has a property, called string TextToCheck. object 有一个名为 string TextToCheck 的属性。 The function should check this property, and if it meets a certain criteria, it needs to ask the user whether he wants to continue with the operation, or not. function要检查这个属性,如果满足一定的条件,就需要询问用户是否要继续操作。 The implementation of the Func<object, bool> function that the DoOperation(Func<object, bool> ConfirmOperation) invokes in itself would go something like this in Windows.Forms: DoOperation(Func<object, bool> ConfirmOperation)本身调用的 Func<object, bool Func<object, bool> function 的实现将 go 类似于 Windows.Forms 中的内容:

private bool ConfirmOperation(object Object) {
    if(Object.TextToCheck == Criteria) {
        if(MessageBox.Show("MESSAGE", "TITLE", MessageBoxButtons.YesNo) == DialogResult.No) {
                return false;
        } else {
            return true;
        }
    } else
        return true;
}

Of couse this blocks the UI, but at least it works, and i don't see any drawbacks from blocking in this particular case.当然,这会阻塞 UI,但至少它是有效的,而且我认为在这种特殊情况下阻塞没有任何缺点。

My question is: how can i implement this private bool ConfirmOperation(object Object) function in my Xamarin.Android project (Android 4.4.2), that prompts the user and returns a bool result based on a Yes/No button press, and does not block the UI?我的问题是:我如何在我的 Xamarin.Android 项目(Android 4.4.2)中实现这个private bool ConfirmOperation(object Object) function,提示用户并根据是/否按钮按下返回 bool 结果,并且不阻止用户界面?

This obviously does not work, because.Show() does not block the UI:这显然是行不通的,因为.Show() 不会阻塞 UI:

private bool ConfirmOperation(object Object) {
    if(Object.TextToCheck!= "AABBCCDD") {
        AlertDialog.Builder AlertDialog = new AlertDialog.Builder(this);
        AlertDialog.SetTitle("Warning!");
        AlertDialog.SetMessage("Do you want to proceed with the operation?");
        AlertDialog.SetNegativeButton("No", (senderAlert, args) => {

                });

        AlertDialog.SetPositiveButton("Yes", (senderAlert, args) => {

                });

        AlertDialog.Show();

        return TheResultFromTheAlertDialog;
    }

    else {
        return true;
    }
}

prompts the user and returns a bool result based on a Yes/No button press, and does not block the UI? 提示用户并基于是/否按钮返回布尔结果,并且不会阻止UI?

Update : 更新:

Here is a more elegant solution, you could display an Alert by using AutoResetEvent and then wrapping it in a Task and call it Async . 这是一个更优雅的解决方案,您可以使用AutoResetEvent来显示Alert,然后将其包装在Task中,并将其称为Async

Example : 范例:

public async Task<bool> DisplayMessage(string titile, string content)
{
    objDialog = new AlertDialog.Builder(this)
       .SetTitle(titile)
       .SetMessage(content)
       .SetCancelable(false)
       .Create();
    bool result = false;

    await Task.Run(() =>
    {
        var waitHandle = new AutoResetEvent(false);
        objDialog.SetButton((int)(DialogButtonType.Positive), "yes", (sender, e) =>
        {
            result = true;
            waitHandle.Set();
        });

        objDialog.SetButton((int)DialogButtonType.Negative, "no", (sender, e) =>
        {
            result = false;
            waitHandle.Set();
        });

        RunOnUiThread(() =>
        {
            objDialog.Show();
        });
        waitHandle.WaitOne();
    });
    objDialog.Dispose();
    return result;
}

Usage : 用法:

button.Click += async (s, e) =>
{
    var result = await DisplayMessage("Title", "Content");
    System.Diagnostics.Debug.WriteLine(result + "=====================");
};

It works perfectly. 它运作完美。


You could use Looper.Loop() to block the UI thread util you get a result from ConfirmOperation method. 您可以使用Looper.Loop()来阻止UI线程, ConfirmOperation您从ConfirmOperation方法获得结果。 Most importantly, this method will not trigger an ANR . 最重要的是, 此方法不会触发ANR

Here is my code : 这是我的代码:

private bool ConfirmOperation(string Object)
    {
        if (Object != "AABBCCDD")
        {
            if (Object == "user_Click_no")
            {
                return false;
            }
            bool TheResultFromTheAlertDialog = false;

            AlertDialog.Builder AlertDialog = new AlertDialog.Builder(this);

            AlertDialog.SetTitle("Warning!");
            AlertDialog.SetMessage("Do you want to proceed with the operation?");
            AlertDialog.SetNegativeButton("No", (senderAlert, args) => {

                Message message = mHandler.ObtainMessage();
                message.What = 1;
                mHandler.SendMessage(message);
            });
            AlertDialog.SetPositiveButton("Yes", (senderAlert, args) => {

                Message message = mHandler.ObtainMessage();
                message.What = 0;
                mHandler.SendMessage(message);
            });


            AlertDialog.Show();

            try { Looper.Loop(); } catch (Java.Lang.Exception e) { }

            return TheResultFromTheAlertDialog;//Actually, it didn't work
        }
        else
        {
            //It's true or user click yes.
            return true;
        }
    }

When it didnt meets your criteria, it will display a Dialog and block the main thread. 当它不符合您的条件时,它将显示一个Dialog并阻止主线程。 Once user click yes or no button, it will send a message and throw new RuntimeException() , as a result, the block will dismiss and you could receive the message in your Handler class. 一旦用户单击“ yes或“ no按钮,它将发送一条消息并抛出新的RuntimeException() ,结果,该块将关闭,您可以在Handler类中接收到该消息。 Then you could call ConfirmOperation method get the result.(Just make a judgement and return a value.) 然后可以调用ConfirmOperation方法获取结果(只需做出判断并返回一个值)。

 mHandler = new MyHandler(this);
 ...

public class MyHandler : Handler
    {
        public MainActivity mainActivity;
        public MyHandler(MainActivity mainActivity)
        {
            this.mainActivity = mainActivity;
        }

        public override void HandleMessage(Message msg)
        {
            try
            {
                throw new RuntimeException();
            }
            catch
            {
            }
            finally
            {
                if (msg.What == 0)//click yes
                {
                    var a = mainActivity.ConfirmOperation("AABBCCDD");//return true;

                    Toast.MakeText(mainActivity, "user_Click_yes", ToastLength.Short).Show();
                }
                else if (msg.What == 1)//click no
                {
                    var a = mainActivity.ConfirmOperation("user_Click_no");//return false;
                    Toast.MakeText(mainActivity, "user_Click_no", ToastLength.Short).Show();
                }
            }
        }
    }

For this case useful TaskCompletionSource class.对于这种情况有用的 TaskCompletionSource class。

When should TaskCompletionSource<T> be used?什么时候应该使用 TaskCompletionSource<T>?

Please, consider implementation of a following extension method请考虑实施以下扩展方法

    public static async Task<bool?> ShowAlertDialogAsync(this Context context,
        string title, string message,
        string positive = default,
        string negative = default,
        string neutral = default)
    {
        var source = new TaskCompletionSource<bool?>();

        new AlertDialog.Builder(context).SetTitle(title).SetMessage(message)
            .SetPositiveButton(positive, (sender, args) => source.SetResult(true))
            .SetNegativeButton(negative, (sender, args) => source.SetResult(false))
            .SetNeutralButton(neutral, (sender, args) => source.SetResult(default))
            .Show();

        return await source.Task;
    }
    

For questions对于问题

    var result = await activity.ShowAlertDialogAsync
    (
        "Question", "Confirm the action?", "Yes", "No"
    );
    
    if (result is true) PerformAction();
    

For notices对于通知

    await activity.ShowAlertDialogAsync
    (
        "Notice", "Hey, you are so fine!", neutral: "Ok"
    );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM