问题
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