11

独自のコントロールを作成したいのですが、ctorが呼び出されると、MessageBoxが表示されます。

public class Class1
{
    public Class1()
    {
        ShowDialog();
    }
    void ShowDialog()
    {
        SynchronizationContext context = SynchronizationContext.Current;
        if (context != null)
        {
            context.Post((f) =>
            {
                MessageDialog dialog = new MessageDialog("Hello!");
                dialog.ShowAsync();
            }, null);
        }
    }
}

私のクラスが誰かによって使用されていて、以下のようにコードを書くと、UnauthorizedAccessExceptionが常にスローされますdialog.ShowAsync();

void MainPage_Loaded(object sender, RoutedEventArgs e)
        {

            ClassLibrary1.Class1 c1 = new ClassLibrary1.Class1();
            MessageDialog dialog1 = new MessageDialog("");
            dialog1.ShowAsync();
        }

例外なくメッセージダイアログを表示する方法はありますか?


私は方法を見つけました、それを楽しんでください!

Task ShowDialog()
        {
            CoreDispatcher dispatcher = Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher;
            Func<object, Task<bool>> action = null;
            action = async (o) =>
            {
                try
                {
                    if (dispatcher.HasThreadAccess)
                        await new MessageDialog("Hello!").ShowAsync();
                    else
                    {
                        dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                        () => action(o));
                    }
                    return true;
                }
                catch (UnauthorizedAccessException)
                {
                    if (action != null)
                    {
                        Task.Delay(500).ContinueWith(async t => await action(o));
                    }
                }
                return false;
            };
            return action(null);
        }
4

4 に答える 4

3

MessageDialogue は UI スレッドで実行する必要があるため、次のように切り替えてみてください。

var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
dispatcher.RunAsync(DispatcherPriority.Normal, <lambda for your code which should run on the UI thread>);
于 2012-12-11T03:20:47.607 に答える
1

よりクリーンなソリューションは次のようになります。興味深い部分は showDialogAsync() に隠されています。便宜上、Close() メソッドを使用して、現在のダイアログをプログラムで再度閉じることができます。IUIDispatcher は、簡単に再構築できるもう 1 つのヘルパー インターフェイスです。

    private readonly IUIDispatcher _dispatcher;
    readonly Object _queueMonitor = new object();
    readonly Object _showMonitor = new object();
    private IAsyncOperation<IUICommand> _currentDialogOperation;
    readonly Queue<MessageDialog> _dialogQueue = new Queue<MessageDialog>();


    public async Task ShowAsync(string content)
    {
        var md = new MessageDialog(content);
        await showDialogAsync(md);
    }

    public async Task ShowAsync(string content, string caption)
    {
        var md = new MessageDialog(content, caption);
        await showDialogAsync(md);
    }

    public async Task<MessageDialogResult> ShowAsync(string content, MessageDialogType dialogType)
    {
        var messageDialogResult = await ShowAsync(content, null, dialogType);
        return messageDialogResult;
    }

    public async Task<MessageDialogResult> ShowAsync(string content, string caption, MessageDialogType dialogType)
    {
        var result = MessageDialogResult.Ok;


            var md = string.IsNullOrEmpty(caption) ?  new MessageDialog(content) : new MessageDialog(content, caption);

        switch (dialogType)
        {
            case MessageDialogType.Ok:
                md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonOk"], command => result = MessageDialogResult.Ok));
                md.CancelCommandIndex = 0;
                md.DefaultCommandIndex = 0;
                break;
            case MessageDialogType.OkCancel:
                md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonOk"], command => result = MessageDialogResult.Ok));
                md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonCancel"], command => result = MessageDialogResult.Cancel));
                md.DefaultCommandIndex = 0;
                md.CancelCommandIndex = 1;
                break;
            case MessageDialogType.YesNo:
                md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonYes"], command => result = MessageDialogResult.Yes));
                md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonNo"], command => result = MessageDialogResult.No));
                  md.DefaultCommandIndex = 0;
                md.CancelCommandIndex = 1;
                break;
            case MessageDialogType.YesNoCancel:
                md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonYes"], command => result = MessageDialogResult.Yes));
                md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonNo"], command => result = MessageDialogResult.No));
                md.Commands.Add(new UICommand(ResWrapper.Strings["MessageDialogButtonCancel"], command => result = MessageDialogResult.Cancel));
                md.DefaultCommandIndex = 0;
                md.CancelCommandIndex = 1;
                break;
            default:
                throw new ArgumentOutOfRangeException("dialogType");
        }

        await showDialogAsync(md);

        return result;
    }


    /// <summary>
    /// Shows the dialogs, queued and one after the other.
    /// We need this as a workaround for the the UnauthorizedAcsess exception. 
    /// </summary>
    /// <param name="messageDialog">The message dialog.</param>
    /// <returns></returns>
    async Task showDialogAsync(MessageDialog messageDialog)
    {
        //Calls this function in a separated task to avoid ui thread deadlocks.
        await Task.Run(async () => 
        { 
            lock (_queueMonitor)
            {
                _dialogQueue.Enqueue(messageDialog);
            }
            try
            {
                while (true)
                {
                    MessageDialog nextMessageDialog;
                    lock (_queueMonitor)
                    {
                        if (_dialogQueue.Count > 1)
                        {
                            Debug.WriteLine("MessageDialogService.cs | showDialogAsync | Next dialog is waiting for MessageDialog to be accessable!!");
                            Monitor.Wait(_queueMonitor); //unlock and wait - regains lock after waiting
                        }

                        nextMessageDialog = _dialogQueue.Peek();
                    }

                    var showing = false;
                    _dispatcher.Execute(async () =>  
                    {
                        try
                        {
                            lock (_showMonitor)
                            {
                                showing = true;
                                _currentDialogOperation = nextMessageDialog.ShowAsync();
                            }

                            await _currentDialogOperation;

                            lock (_showMonitor)
                                _currentDialogOperation = null;
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine("MessageDialogService.cs | showDialogAsync | " + e);
                        }
                        lock (_showMonitor)
                        {
                            showing = false;
                            Monitor.Pulse(_showMonitor); //unlock and wait - regains lock after waiting
                        }
                    });


                    lock (_showMonitor)
                    {
                        if (showing)
                        {
                            Debug.WriteLine("MessageDialogService.cs | showDialogAsync | Waiting for MessageDialog to be closed!!");
                            //we must wait here manually for the closing of the dialog, because the dispatcher does not return a waitable task.
                            Monitor.Wait(_showMonitor); //unlock and wait - regains lock after waiting
                        }
                    }
                    Debug.WriteLine("MessageDialogService.cs | showDialogAsync | MessageDialog  was closed.");
                    return true;
                }
            }
            finally
            {
                //make sure we leave this in a clean state
                lock (_queueMonitor)
                {
                    _dialogQueue.Dequeue();
                    Monitor.Pulse(_queueMonitor);
                }
            }
        });
    }


    public void Close(string keyContent="")
    {
        try
        {
            if (keyContent.IsNullOrEmpty())
            {
                lock (_showMonitor)
                {
                    if (_currentDialogOperation == null) return;
                    _currentDialogOperation.Cancel();
                    _currentDialogOperation = null;
                }
            }
            else
            {
                var cancel = false;
                lock (_queueMonitor)
                {
                    if (_dialogQueue.Count == 0)
                        return;

                    var currentDialog = _dialogQueue.Peek();

                    Debug.WriteLine("MessageDialogService.cs | Close | {0}", currentDialog.Content);
                    if (currentDialog.Content == keyContent)
                    {
                        cancel = true;
                    }
                }
                if (!cancel) return;
                lock (_showMonitor)
                {
                    if (_currentDialogOperation == null) return;
                    _currentDialogOperation.Cancel();
                    _currentDialogOperation = null;
                }
            }
        }
        catch (Exception e)
        {
            Debug.WriteLine("MessageDialogService.cs | Close | " + e);
        }

    }
于 2013-10-16T13:00:37.443 に答える
0

いつも使えます

Execute.OnUIThread( async () => {
...
var dialog = new MessageDialog(yourMessage);
await dialog.ShowAsync();
...
});

バックグラウンド スレッドから複数のダイアログを起動しようとしている場合、これは UI の競合状態を解決しません。ただし、try/catch を使用して、そのケースを確実にカバーすることができます。

于 2013-04-23T05:11:30.883 に答える
0

私はそれを見つけたと思います。メインスレッド以外のスレッドでメッセージボックスを作成するときに同じ問題が発生しました。これは C++ のソリューションですが、簡単に変換できると思います ;)

    IAsyncOperation<IUICommand^> ^Op = msgbox->ShowAsync();
    task<IUICommand^>( Op ).then([=](IUICommand^ C)
    {

    }).then([](task<void> t) 
        {
            try 
            {
                t.get();
            }
            catch (Platform::Exception ^e)
            {   
                //ERROR!                            
            }           
        });

ちなみに、これは WinRT/Windows 8 Store C++ 例外を処理する正しい方法です。

于 2013-01-25T07:23:52.000 に答える