【问题标题】:How to avoid async methods windows phone 8.1如何避免异步方法 windows phone 8.1
【发布时间】:2014-09-08 16:44:51
【问题描述】:

我正在创建一个 windows phone 8.1 应用程序。当应用程序启动时,应用程序会提示用户拨打某个电话号码。它通过语音来做到这一点。应用程序告知指令后,将显示电话对话框。 这是代码:

public MainPage()
    {
        this.InitializeComponent();

        this.NavigationCacheMode = NavigationCacheMode.Required;
        StartSpeaking("Please call number !");

        CallDialog();
    }

    private async void StartSpeaking(string text)
    {

        MediaElement mediaElement = this.media;

        // The object for controlling the speech synthesis engine (voice).
        var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();

        // Generate the audio stream from plain text.
        SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(text);

        // Send the stream to the media object.
         mediaElement.SetSource(stream, stream.ContentType);
        mediaElement.Play();



    }

 private async void CallDialog()
    {

        Windows.ApplicationModel.Calls.PhoneCallManager.ShowPhoneCallUI("123", "123");
        var messageDialog = new Windows.UI.Popups.MessageDialog("call ended", "Text spoken");
        await messageDialog.ShowAsync();
    }

问题是我必须使用 synth.SynthesizeTextToStreamAsync 方法,它是异步方法,所以调用对话框会在文本说之前出现。我怎样才能避免这种情况?

【问题讨论】:

    标签: c# asynchronous speech-recognition windows-phone-8.1 speech-to-text


    【解决方案1】:

    async Task 方法应该被接受;只有async void 方法应该避免(它们应该只用作事件处理程序)。我有一个MSDN article that describes a few reasons to avoid async void

    在您的情况下,您可以使用async void 事件处理程序(例如,用于Loaded 事件),并使您的方法async Task 而不是async voidawait 它们:

    async void MainPage_Loaded(..)
    {
      await StartSpeakingAsync("Please call number !");
      await CallDialogAsync();
    }
    
    private async Task StartSpeakingAsync(string text);
    private async Task CallDialogAsync();
    

    更新

    要(异步)等待媒体播放,您需要挂钩一个通知您播放完成的事件。 MediaEnded 看起来是个不错的选择。像这样的东西应该可以工作:

    public static Task PlayToEndAsync(this MediaElement @this)
    {
      var tcs = new TaskCompletionSource<object>();
      RoutedEventHandler subscription = null;
      subscription = (_, __) =>
      {
        @this.MediaEnded -= subscription;
        tcs.TrySetResult(null);
      };
      @this.MediaEnded += subscription;
      @this.Play();
      return tcs.Task;
    }
    

    该方法使用async-ready PlayToEndAsync 方法扩展MediaElement,您可以像这样使用它:

    private async Task SpeakAsync(string text)
    {
      MediaElement mediaElement = this.media;
      var synth = new Windows.Media.SpeechSynthesis.SpeechSynthesizer();
      SpeechSynthesisStream stream = await synth.SynthesizeTextToStreamAsync(text);
      mediaElement.SetSource(stream, stream.ContentType);
      await mediaElement.PlayToEndAsync();
    }
    

    【讨论】:

    • 是的,我明白这一点,但即使我这样做,我仍然会在应用程序启动时立即收到通话对话框,而不是在它之前拨打电话号码。
    猜你喜欢
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-17
    • 1970-01-01
    相关资源
    最近更新 更多