Экземпляр Messagebox.Show и DialogResult в MonoTouch - PullRequest
16 голосов
/ 06 января 2011

У меня есть диалог Да / Нет из UIAlertView с двумя кнопками.Я хотел бы в моем методе реализовать логику, подобную этой:

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

Дело в том, что если я вызываю UIAlertView.Show (), процесс продолжается.Но мне нужно дождаться результата взаимодействия с пользователем и вернуть истину или ложь, нажав на вторую кнопку.Возможно ли это в MonoTouch?

Ответы [ 6 ]

18 голосов
/ 26 января 2011

Для этого вы можете запустить основной цикл вручную.Мне не удалось остановить основной цикл напрямую, поэтому я вместо этого запускаю основной цикл в течение 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;
}
17 голосов
/ 27 марта 2012

Основываясь на кодировке Мигеля, вот удобная замена стандартному 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 голос
/ 01 марта 2014

Я думаю, что этот подход, использующий async / await, намного лучше, и он не страдает от зависания приложения при повороте устройства, или когда автоматическая прокрутка мешает и оставляет вас застрявшими в цикле RunUntil навсегда без возможности нажать кнопку (по крайней мере, эти проблемы легко воспроизвести на iOS7).

Модальный 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 голосов
/ 25 января 2018

Вот еще одно обновление, основанное на материалах, сделанных Мигелем, Алесом, Дэнмистером и Патриком.

С момента выхода 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;
    }
}
0 голосов
/ 16 апреля 2015

Комбинированные ответы данмизера и Алеса

            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 голосов
/ 06 января 2011

MonoTouch (iOS) не имеет модальных диалогов, причина в том, что модальные диалоги (ожидающие) могут вызывать взаимные блокировки, поэтому фреймворки, такие как Silverlight, Flex / Flash, iOS, не допускают такие диалоги.

Единственный способ, которым выможет работать с ним, вы должны передать делегат в UIAlertView, который будет вызван, когда он был успешным.Я не знаю точный синтаксис UIAlertView, но вы должны увидеть документацию по UIAlertView, должен быть способ передать класс, реализующий протокол / интерфейс UIAlertViewDelegate.У него будет метод, который будет вызываться при завершении диалогового окна.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...