11

私は自分のコントロールを作成したい、ctorが呼び出されるとMessageBoxが表示されます。WinRT - MessageDialog.ShowAsyncは、私のカスタムクラスでUnauthorizedAccessExceptionをスローします

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

これは苦しいです。 UIが既に表示されているときは、メッセージボックスを表示することはできません。これは連動させる必要がありますが、もちろんやりにくいです。本当の治療法はありませんが、ワーカースレッドが自分でボックスを押すのを避けてください。 –

+0

回避策としてShowDialogメソッドを変更する方法を見つける – glover

+0

これは実際の修正ではありません。 ShowAsync()を呼び出すコードを書かなかった場合はどうなりますか?まだkaboom。 –

答えて

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

動作しません。実際、この効果はSynchronizationContext.PostまたはWindows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsyncと同じです。それらはすべてUIスレッドでダイアログを表示するために使用されます。 – glover

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店舗C++の例外を処理するための正しい方法です。

0

あなたはいつもあなたがバックグラウンドスレッドから複数のダイアログを起動しようとしている場合、これはUIで競合状態を解決しない

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

を使用することができます。しかし、あなたはtry/catchを使ってそのケースをカバーすることができます。

1

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

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

    } 
関連する問題