2011-01-06 9 views
16

私はUIAlertViewからYes/Noダイアログを2つのボタンで持っています。私はUIAlertView.Showを呼び出す場合MessageBox.ShowとDialogResultはMonoTouchで同等です

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

ものがある()プロセスが続く:私はこれと同様のロジックを実装するために私の方法にしたいと思います。しかし、私は、ユーザーインタラクションの結果を待って、2番目のボタンをクリックするとtrueまたはfalseを返す必要があります。 MonoTouchでこれは可能ですか?

答えて

18

これを行うには、メインループを手動で実行する必要があります。私はmainloopを直接停止させていないので、代わりに0.5秒間mainloopを実行し、ユーザーが応答するまで待ってください。

次の関数を使用して、上記の方法でモーダルクエリを実装する方法を示しています。

ミゲルのコード化に基づいて
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

私はこれほど長い間これを行う方法を探していて、 "いいえ"という答えを2つ持っています。そして、Miguelが来ます! :-) – Krumelur

+0

私はMonoDevelopが現在ボタンの種類をUIButtonArgs(この場合はLambda?)として識別していないと言っていますが、私は確かにしたいと思っています。 (自動補完のため、ButtonIndexを表示していないので、オブジェクトとして扱っているようです) –

+0

MonoDevelop 3.1.1でこのエラーが発生しました:[エラー]致命的な未処理例外:MonoTouch.UIKit.UIKitThreadAccessException:UIKit整合性エラー:あなたはUIスレッドからのみ呼び出すことができるUIKitメソッドを呼び出しています。 –

0

MonoTouch(iOS)にはモーダルダイアログがないため、モーダルダイアログ(待機中)がデッドロックを引き起こし、Silverlight、Flex/Flash、iOSなどのフレームワークでこのようなダイアログが許可されません。

あなたがそれを扱う唯一の方法は、UIAlertViewに代理人を渡す必要があり、それが成功したときに呼び出されます。私はUIAlertViewの正確な構文を知っていませんが、UIAlertViewに関するドキュメントを参照する必要があります。UIAlertViewDelegateプロトコル/インターフェイスを実装するクラスを渡す方法が必要です。ダイアログボックスの完成時に呼び出されるメソッドがあります。

+0

iOSの残念なことができますモーダルダイアログ:それはAppleが独自のプッシュ通知警告のために使用するものです。 – ptnik

+0

@ptnik Appleによって内部的に使用される可能性がありますが、モーダルダイアログを許可すると問題が発生します。 –

17

、ここでは標準メッセージボックスの便利な交換です:

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

これはMessageBoxの非常に優れた実装で、私はコードを書く時間を節約します! – jharr100

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とパトリックの貢献に基づいて、別の更新です。

iOS 11、特にバージョン11.1.2がリリースされて以来(私は最初にこれに気づきました)、私が投稿した元のソリューション(Ales)は信頼性がなくなり、ランダムにフリーズし始めました。これは、明示的に呼び出された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; 
    } 
} 
関連する問題