[英]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
。
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;
}
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.