我有一個UIAlertView有兩個按鈕的Yes/No對話框。我想在我的方法來實現類似這樣的邏輯:在MonoTouch中相當於Messagebox.Show和DialogResult
if(messagebox.Show() == DialogResult.OK)
的事情是,如果我叫UIAlertView.Show()過程仍在繼續。但是我需要等待用戶交互的結果,並在單擊第二個按鈕時返回真或假的取消。這在MonoTouch中可能嗎?
我有一個UIAlertView有兩個按鈕的Yes/No對話框。我想在我的方法來實現類似這樣的邏輯:在MonoTouch中相當於Messagebox.Show和DialogResult
if(messagebox.Show() == DialogResult.OK)
的事情是,如果我叫UIAlertView.Show()過程仍在繼續。但是我需要等待用戶交互的結果,並在單擊第二個按鈕時返回真或假的取消。這在MonoTouch中可能嗎?
要做到這一點,你可以做的是手動運行主循環。我沒有設法直接停止主循環,所以我運行0.5秒的主循環並等待用戶響應。
下面的函數顯示瞭如何執行上述方法模態查詢:基於
int WaitForClick()
{
int clicked = -1;
var x = new UIAlertView ("Title", "Message", null, "Cancel", "OK", "Perhaps");
x.Show();
bool done = false;
x.Clicked += (sender, buttonArgs) => {
Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
clicked = buttonArgs.ButtonIndex;
};
while (clicked == -1){
NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.5));
Console.WriteLine ("Waiting for another 0.5 seconds");
}
Console.WriteLine ("The user clicked {0}", clicked);
return clicked;
}
MonoTouch(iOS)沒有Modal對話框,原因是Modal對話框(等待)會導致死鎖,所以像Silverlight,Flex/Flash,iOS這樣的框架不允許這樣的對話框。
您可以使用它的唯一方法是,您必須將委託傳遞給UIAlertView,它將在成功時調用。我不知道UIAlertView的確切語法,但您應該看到有關UIAlertView的文檔,必須有一種方法來傳遞實現UIAlertViewDelegate協議/接口的類。這將有一個方法,將在完成對話框時調用。
iOS的不幸使模態對話框:這就是蘋果使用其自己的推送通知提醒。 – ptnik 2011-01-06 09:59:49
@ptnik可能被Apple內部使用,但如果它們允許模式對話框,則會產生問題。 – 2011-01-06 10:31:51
米格爾的編碼,這裏是一個方便的更換標準的MessageBox的:
using System;
using System.Drawing;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using System.Collections.Generic;
namespace YourNameSpace
{
public enum MessageBoxResult
{
None = 0,
OK,
Cancel,
Yes,
No
}
public enum MessageBoxButton
{
OK = 0,
OKCancel,
YesNo,
YesNoCancel
}
public static class MessageBox
{
public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton buttonType)
{
MessageBoxResult res = MessageBoxResult.Cancel;
bool IsDisplayed = false;
int buttonClicked = -1;
MessageBoxButton button = buttonType;
UIAlertView alert = null;
string cancelButton = "Cancel";
string[] otherButtons = null;
switch (button)
{
case MessageBoxButton.OK:
cancelButton = "";
otherButtons = new string[1];
otherButtons[0] = "OK";
break;
case MessageBoxButton.OKCancel:
otherButtons = new string[1];
otherButtons[0] = "OK";
break;
case MessageBoxButton.YesNo:
cancelButton = "";
otherButtons = new string[2];
otherButtons[0] = "Yes";
otherButtons[1] = "No";
break;
case MessageBoxButton.YesNoCancel:
otherButtons = new string[2];
otherButtons[0] = "Yes";
otherButtons[1] = "No";
break;
}
if (cancelButton.Length > 0)
alert = new UIAlertView(caption, messageBoxText, null, cancelButton, otherButtons);
else
alert = new UIAlertView(caption, messageBoxText, null, null, otherButtons);
alert.BackgroundColor = UIColor.FromWhiteAlpha(0f, 0.8f);
alert.Canceled += (sender, e) => {
buttonClicked = 0;
IsDisplayed = false;
};
alert.Clicked += (sender, e) => {
buttonClicked = e.ButtonIndex;
IsDisplayed = false;
};
alert.Dismissed += (sender, e) => {
if (IsDisplayed)
{
buttonClicked = e.ButtonIndex;
IsDisplayed = false;
}
};
alert.Show();
IsDisplayed = true;
while (IsDisplayed)
{
NSRunLoop.Current.RunUntil (NSDate.FromTimeIntervalSinceNow (0.2));
}
switch (button)
{
case MessageBoxButton.OK:
res = MessageBoxResult.OK;
break;
case MessageBoxButton.OKCancel:
if (buttonClicked == 1)
res = MessageBoxResult.OK;
break;
case MessageBoxButton.YesNo:
if (buttonClicked == 0)
res = MessageBoxResult.Yes;
else
res = MessageBoxResult.No;
break;
case MessageBoxButton.YesNoCancel:
if (buttonClicked == 1)
res = MessageBoxResult.Yes;
else if (buttonClicked == 2)
res = MessageBoxResult.No;
break;
}
return res;
}
public static MessageBoxResult Show(string messageBoxText)
{
return Show(messageBoxText, "", MessageBoxButton.OK);
}
public static MessageBoxResult Show(string messageBoxText, string caption)
{
return Show(messageBoxText, caption, MessageBoxButton.OK);
}
}
}
我認爲這種使用async/await的方法要好得多,並且不會在旋轉設備時凍結應用程序,或者當自動滾動干擾並且讓您永遠卡在RunUntil循環中而無法單擊按鈕時(至少這些問題很容易在iOS7上重現)。
Task<int> ShowModalAletViewAsync (string title, string message, params string[] buttons)
{
var alertView = new UIAlertView (title, message, null, null, buttons);
alertView.Show();
var tsc = new TaskCompletionSource<int>();
alertView.Clicked += (sender, buttonArgs) => {
Console.WriteLine ("User clicked on {0}", buttonArgs.ButtonIndex);
tsc.TrySetResult(buttonArgs.ButtonIndex);
};
return tsc.Task;
}
結合danmiser和強麥的答案
using System;
using System.Drawing;
using MonoTouch.UIKit;
using MonoTouch.Foundation;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace yournamespace
{
public enum MessageBoxResult
{
None = 0,
OK,
Cancel,
Yes,
No
}
public enum MessageBoxButton
{
OK = 0,
OKCancel,
YesNo,
YesNoCancel
}
public static class MessageBox
{
public static Task<MessageBoxResult> ShowAsync(string messageBoxText, string caption, MessageBoxButton buttonType)
{
MessageBoxResult res = MessageBoxResult.Cancel;
bool IsDisplayed = false;
int buttonClicked = -1;
MessageBoxButton button = buttonType;
UIAlertView alert = null;
string cancelButton = "Cancel";
string[] otherButtons = null;
switch (button)
{
case MessageBoxButton.OK:
cancelButton = "";
otherButtons = new string[1];
otherButtons[0] = "OK";
break;
case MessageBoxButton.OKCancel:
otherButtons = new string[1];
otherButtons[0] = "OK";
break;
case MessageBoxButton.YesNo:
cancelButton = "";
otherButtons = new string[2];
otherButtons[0] = "Yes";
otherButtons[1] = "No";
break;
case MessageBoxButton.YesNoCancel:
otherButtons = new string[2];
otherButtons[0] = "Yes";
otherButtons[1] = "No";
break;
}
var tsc = new TaskCompletionSource<MessageBoxResult>();
if (cancelButton.Length > 0)
alert = new UIAlertView(caption, messageBoxText, null, cancelButton, otherButtons);
else
alert = new UIAlertView(caption, messageBoxText, null, null, otherButtons);
alert.BackgroundColor = UIColor.FromWhiteAlpha(0f, 0.8f);
alert.Canceled += (sender, e) => {
tsc.TrySetResult(MessageBoxResult.Cancel);
};
alert.Clicked += (sender, e) => {
buttonClicked = e.ButtonIndex;
switch (button)
{
case MessageBoxButton.OK:
res = MessageBoxResult.OK;
break;
case MessageBoxButton.OKCancel:
if (buttonClicked == 1)
res = MessageBoxResult.OK;
break;
case MessageBoxButton.YesNo:
if (buttonClicked == 0)
res = MessageBoxResult.Yes;
else
res = MessageBoxResult.No;
break;
case MessageBoxButton.YesNoCancel:
if (buttonClicked == 1)
res = MessageBoxResult.Yes;
else if (buttonClicked == 2)
res = MessageBoxResult.No;
break;
}
tsc.TrySetResult(res);
};
alert.Show();
return tsc.Task;
}
public static Task<MessageBoxResult> ShowAsync(string messageBoxText)
{
return ShowAsync(messageBoxText, "", MessageBoxButton.OK);
}
public static Task<MessageBoxResult> ShowAsync(string messageBoxText, string caption)
{
return ShowAsync(messageBoxText, caption, MessageBoxButton.OK);
}
}
}
這裏是另一個更新的基礎上,由米格爾,強麥,danmister和帕特里克貢獻。我自己發佈的原始解決方案(Ales)變得不可靠,開始隨機凍結。因爲iOS 11的發佈,特別是版本11.1.2(我首先注意到它),我發佈的原始解決方案變得不可靠,開始隨機凍結。這一個明確地調用了NSRunLoop.Current.RunUntil()。
因此,我更新了我的原始類,以實際提供同步和異步方法,並執行了一些其他更改,以便在單擊任何按鈕後立即釋放內存,還添加了將文本對齊到左側的代碼(如果Windows檢測到CRLF換行符。
命名空間:
using System;
using CoreGraphics;
using UIKit;
using Foundation;
using System.Collections.Generic;
using System.Threading.Tasks;
代碼:
public enum MessageBoxResult
{
None = 0,
OK,
Cancel,
Yes,
No
}
public enum MessageBoxButton
{
OK = 0,
OKCancel,
YesNo,
YesNoCancel
}
public static class MessageBox
{
/* This class emulates Windows style modal boxes. Unfortunately, the original code doesn't work reliably since cca iOS 11.1.2 so
* you have to use the asynchronous methods provided here.
*
* The code was a bit restructured utilising class MessageBoxNonstatic to make sure that on repeated use, it doesn't allocate momere memory.
* Note that event handlers are explicitly removed and at the end I explicitly call garbage collector.
*
* The code is a bit verbose to make it easier to understand and open it to tweaks.
*
*/
// Synchronous methods - don't work well since iOS 11.1.2, often freeze because something has changed in the event loop and
// NSRunLoop.Current.RunUntil() is not reliable to use anymore
public static MessageBoxResult Show(string messageBoxText, string caption, MessageBoxButton buttonType)
{
MessageBoxNonstatic box = new MessageBoxNonstatic();
return box.Show(messageBoxText, caption, buttonType);
}
public static MessageBoxResult Show(string messageBoxText)
{
return Show(messageBoxText, "", MessageBoxButton.OK);
}
public static MessageBoxResult Show(string messageBoxText, string caption)
{
return Show(messageBoxText, caption, MessageBoxButton.OK);
}
// Asynchronous methods - use with await keyword. Restructure the calling code tho accomodate async calling patterns
// See https://docs.microsoft.com/en-us/dotnet/csharp/async
/*
async void DecideOnQuestion()
{
if (await MessageBox.ShowAsync("Proceed?", "DECIDE!", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
// Do something
}
}
*/
public static Task<MessageBoxResult> ShowAsync(string messageBoxText, string caption, MessageBoxButton buttonType)
{
MessageBoxNonstatic box = new MessageBoxNonstatic();
return box.ShowAsync(messageBoxText, caption, buttonType);
}
public static Task<MessageBoxResult> ShowAsync(string messageBoxText)
{
return ShowAsync(messageBoxText, "", MessageBoxButton.OK);
}
public static Task<MessageBoxResult> ShowAsync(string messageBoxText, string caption)
{
return ShowAsync(messageBoxText, caption, MessageBoxButton.OK);
}
}
public class MessageBoxNonstatic
{
private bool IsDisplayed = false;
private int buttonClicked = -1;
private UIAlertView alert = null;
private string messageBoxText = "";
private string caption = "";
private MessageBoxButton button = MessageBoxButton.OK;
public bool IsAsync = false;
TaskCompletionSource<MessageBoxResult> tsc = null;
public MessageBoxNonstatic()
{
// Do nothing
}
public MessageBoxResult Show(string sMessageBoxText, string sCaption, MessageBoxButton eButtonType)
{
messageBoxText = sMessageBoxText;
caption = sCaption;
button = eButtonType;
IsAsync = false;
ShowAlertBox();
WaitInLoopWhileDisplayed();
return GetResult();
}
public Task<MessageBoxResult> ShowAsync(string sMessageBoxText, string sCaption, MessageBoxButton eButtonType)
{
messageBoxText = sMessageBoxText;
caption = sCaption;
button = eButtonType;
IsAsync = true;
tsc = new TaskCompletionSource<MessageBoxResult>();
ShowAlertBox();
return tsc.Task;
}
private void ShowAlertBox()
{
IsDisplayed = false;
buttonClicked = -1;
alert = null;
string cancelButton = "Cancel";
string[] otherButtons = null;
switch (button)
{
case MessageBoxButton.OK:
cancelButton = "";
otherButtons = new string[1];
otherButtons[0] = "OK";
break;
case MessageBoxButton.OKCancel:
otherButtons = new string[1];
otherButtons[0] = "OK";
break;
case MessageBoxButton.YesNo:
cancelButton = "";
otherButtons = new string[2];
otherButtons[0] = "Yes";
otherButtons[1] = "No";
break;
case MessageBoxButton.YesNoCancel:
otherButtons = new string[2];
otherButtons[0] = "Yes";
otherButtons[1] = "No";
break;
}
IUIAlertViewDelegate d = null;
if (cancelButton.Length > 0)
alert = new UIAlertView(caption, messageBoxText, d, cancelButton, otherButtons);
else
alert = new UIAlertView(caption, messageBoxText, d, null, otherButtons);
if (messageBoxText.Contains("\r\n"))
{
foreach (UIView v in alert.Subviews)
{
try
{
UILabel l = (UILabel)v;
if (l.Text == messageBoxText)
{
l.TextAlignment = UITextAlignment.Left;
}
}
catch
{
// Do nothing
}
}
}
alert.BackgroundColor = UIColor.FromWhiteAlpha(0f, 0.8f);
alert.Canceled += Canceled_Click;
alert.Clicked += Clicked_Click;
alert.Dismissed += Dismissed_Click;
alert.Show();
IsDisplayed = true;
}
// ======================================================================= Private methods ==========================================================================
private void WaitInLoopWhileDisplayed()
{
while (IsDisplayed)
{
NSRunLoop.Current.RunUntil(NSDate.FromTimeIntervalSinceNow(0.2));
}
}
private void Canceled_Click(object sender, EventArgs e)
{
buttonClicked = 0;
IsDisplayed = false;
DisposeAlert();
}
private void Clicked_Click(object sender, UIButtonEventArgs e)
{
buttonClicked = (int)e.ButtonIndex;
IsDisplayed = false;
DisposeAlert();
}
private void Dismissed_Click(object sender, UIButtonEventArgs e)
{
if (IsDisplayed)
{
buttonClicked = (int)e.ButtonIndex;
IsDisplayed = false;
DisposeAlert();
}
}
private void DisposeAlert()
{
alert.Canceled -= Canceled_Click;
alert.Clicked -= Clicked_Click;
alert.Dismissed -= Dismissed_Click;
alert.Dispose();
alert = null;
GC.Collect();
if (IsAsync)
GetResult();
}
private MessageBoxResult GetResult()
{
MessageBoxResult res = MessageBoxResult.Cancel;
switch (button)
{
case MessageBoxButton.OK:
res = MessageBoxResult.OK;
break;
case MessageBoxButton.OKCancel:
if (buttonClicked == 1)
res = MessageBoxResult.OK;
break;
case MessageBoxButton.YesNo:
if (buttonClicked == 0)
res = MessageBoxResult.Yes;
else
res = MessageBoxResult.No;
break;
case MessageBoxButton.YesNoCancel:
if (buttonClicked == 1)
res = MessageBoxResult.Yes;
else if (buttonClicked == 2)
res = MessageBoxResult.No;
break;
}
if (IsAsync)
tsc.TrySetResult(res);
return res;
}
}
因爲我一直在尋找一種這麼做的方法,並且得到了幾個「不能做」的答案 - 然後Miguel就來了! :-) – Krumelur 2011-01-27 19:57:04