MonoTouch中的Messagebox.Show和DialogResult等效

时间:2011-01-06 08:31:01

标签: c# iphone ipad xamarin.ios

我有一个带有两个按钮的UIAlertView的是/否对话框。我希望在我的方法中实现类似于此的逻辑:

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

问题是,如果我调用UIAlertView.Show(),该过程将继续。但我需要等待用户交互的结果,并在单击第二个按钮时返回true或false depanding。这在MonoTouch中是否可行?

6 个答案:

答案 0 :(得分:18)

要做到这一点,你可以做的是手动运行mainloop。我没有设法直接停止主循环,所以我改为运行主循环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;
}

答案 1 :(得分:17)

基于Miguel的编码,这里是标准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);
        }
    }
}

答案 2 :(得分: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;
}       

答案 3 :(得分:0)

MonoTouch(iOS)没有模态对话框,原因是模态对话框(等待)会导致死锁,因此像Silverlight,Flex / Flash,iOS这样的框架不允许这样的对话框。

你可以使用它的唯一方法是,你必须将一个委托传递给UIAlertView,它将在成功时被调用。我不知道UIAlertView的确切语法,但您应该看到有关UIAlertView的文档,必须有一种方法来传递实现UIAlertViewDelegate协议/接口的类。这将有一个方法,将在完成对话框时调用。

答案 4 :(得分:0)

danmiser和Ales&#39;答案

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

答案 5 :(得分:0)

这是另一个更新,基于Miguel,Ales,danmister和Patrick的贡献。

自从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;
    }
}