11

में अनधिकृत एक्सेस अपवाद फेंक देगा, जब मैं ctor आह्वान करता हूं, तो अपना नियंत्रण लिखना चाहता हूं, एक संदेशबॉक्स दिखाया जाता है।WinRT - MessageDialog.ShowAsync मेरी कस्टम क्लास

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

अच्छा, यह दर्दनाक है। यूआई पहले से ही एक दिखा रहा है जब आप एक संदेश बॉक्स नहीं दिखा सकते हैं। यह निश्चित रूप से करने के लिए बहुत मुश्किल है, interlocked करने की जरूरत है। कोई वास्तविक इलाज नहीं है लेकिन कार्यकर्ता धागे से खुद को धक्का देने से बचें। –

+0

मुझे एक तरीका मिल गया है, केवल ShowDialog विधि को वर्कअराउंड – glover

+0

के रूप में संशोधित करें, ठीक है, यह वास्तविक फ़िक्स नहीं है। कोड के साथ क्या होता है जिसे आपने नहीं लिखा था जो ShowAsync() को कॉल करता है। अभी भी एक कबूतर –

उत्तर

3

MessageDialogue यूआई धागे पर चलाने की आवश्यकता के रूप में, आप के लिए यह परिवर्तित करने का प्रयास कर सकते हैं:

var dispatcher = Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher; 
dispatcher.RunAsync(DispatcherPriority.Normal, <lambda for your code which should run on the UI thread>); 
+0

यह काम नहीं करता है। असल में, प्रभाव सिंक्रनाइज़ेशन कॉन्टेक्स्ट.पोस्ट या विंडोज़ के रूप में समान है। अनुप्रयोग मॉडेल.कोर.कोर एप्प्लिकेशंस.माइन व्यू.कोरविंडो। डिस्पैचर.रुनएसिंक। उन सभी का उपयोग यूआई थ्रेड में संवाद दिखाने के लिए किया जाता है। – glover

0

मुझे लगता है कि मैं इसे पाया है। मुख्य धागे के अलावा किसी अन्य धागे में संदेशबॉक्स बनाते समय मुझे भी यही समस्या थी। यह सी ++ समाधान है, लेकिन मैं आप इसे आसानी से परिवर्तित कर सकते हैं लगता है;)

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

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

एक तरफ ध्यान दें पर इस किसी भी WinRT/विंडोज 8 स्टोर C++ अपवाद को संभालने के लिए सही तरीका है।

0

तुम हमेशा

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

उपयोग कर सकते हैं यह यूआई में दौड़ की स्थिति का समाधान नहीं होता है, तो आप पृष्ठभूमि धागे से कई संवाद शुरू करने के लिए कोशिश कर रहे हैं। लेकिन आप यह सुनिश्चित करने के लिए एक प्रयास/पकड़ का उपयोग कर सकते हैं कि आप उस मामले के लिए कवर करते हैं।

1

क्लीनर समाधान इस तरह दिख सकता है। दिलचस्प हिस्सा मर गया शो DialogAsync() में छिपा हुआ है। सुविधा के लिए आप प्रोग्राम को स्वचालित रूप से चालू संवाद को बंद करने के लिए बंद() विधि का उपयोग कर सकते हैं। 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); 
     } 

    }