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

微笑、不失礼 提交于 2019-12-24 19:18:34

问题


I have to use a function in my Xamarin project, which has a DoOperation(Func<object, bool> ConfirmOperation) overload. The object has a property, called 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. 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:

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.

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?

This obviously does not work, because .Show() does not block the 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;
    }
}

回答1:


prompts the user and returns a bool result based on a Yes/No button press, and does not block the 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.

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. Most importantly, this method will not trigger an 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. 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. Then you could call ConfirmOperation method get the result.(Just make a judgement and return a value.)

 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();
                }
            }
        }
    }


来源:https://stackoverflow.com/questions/45701662/returning-a-true-false-value-from-a-funcobject-bool-implementation-with-an-an

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!