2011-01-06 46 views
16

我有一個UIAlertView有兩個按鈕的Yes/No對話框。我想在我的方法來實現類似這樣的邏輯:在MonoTouch中相當於Messagebox.Show和DialogResult

if(messagebox.Show() == DialogResult.OK) 

的事情是,如果我叫UIAlertView.Show()過程仍在繼續。但是我需要等待用戶交互的結果,並在單擊第二個按鈕時返回真或假的取消。這在MonoTouch中可能嗎?

回答

18

要做到這一點,你可以做的是手動運行主循環。我沒有設法直接停止主循環,所以我運行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; 
} 
+0

因爲我一直在尋找一種這麼做的方法,並且得到了幾個「不能做」的答案 - 然後Miguel就來了! :-) – Krumelur 2011-01-27 19:57:04

0

MonoTouch(iOS)沒有Modal對話框,原因是Modal對話框(等待)會導致死鎖,所以像Silverlight,Flex/Flash,iOS這樣的框架不允許這樣的對話框。

您可以使用它的唯一方法是,您必須將委託傳遞給UIAlertView,它將在成功時調用。我不知道UIAlertView的確切語法,但您應該看到有關UIAlertView的文檔,必須有一種方法來傳遞實現UIAlertViewDelegate協議/接口的類。這將有一個方法,將在完成對話框時調用。

+0

iOS的不幸使模態對話框:這就是蘋果使用其自己的推送通知提醒。 – ptnik 2011-01-06 09:59:49

+0

@ptnik可能被Apple內部使用,但如果它們允許模式對話框,則會產生問題。 – 2011-01-06 10:31:51

17

米格爾的編碼,這裏是一個方便的更換標準的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); 
     } 
    } 
} 
1

我認爲這種使用async/await的方法要好得多,並且不會在旋轉設備時凍結應用程序,或者當自動滾動干擾並且讓您永遠卡在RunUntil循環中而無法單擊按鈕時(至少這些問題很容易在iOS7上重現)。

Modal UIAlertView

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; 
}  
0

結合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); 
        } 
       } 
      } 
0

這裏是另一個更新的基礎上,由米格爾,強麥,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; 
    } 
}