【问题标题】:Disable a button, when a Task is completed任务完成时禁用按钮
【发布时间】:2022-10-23 21:20:58
【问题描述】:

我有一个方法,它检查是否可以按下按钮,如果我的文件路径或语言为空,我不启用按钮,当然,当我的文件路径被选中时,我会引发事件。

所以现在我在 Azure 上做一些工作,我想在开始工作时禁用该按钮,并在完成工作时启用它。

我试图在调用方法之前和调用之后引发事件,但它没有启用按钮

        public string? FilePath { get; set; }

        public bool IsWorking { get; set; }

        public Dictionary<int, Languages>? LanguagesDictionary { get; set; }

        public Visibility CanShow { get; set; }

        public DialogHelper DialogHelper { get; }

        public FolderHelper FolderHelper { get; }

        public AudioHelper AudioHelper { get; }

        public AzureTranscriptionService AzureTranscription { get; }

        public Command PickFileCommad { get; set; }

        public Command StartCommand { get; set; }

        private string? _SelectedItem;

        public string SelectedItem {
            get => _SelectedItem!;
            set {
                if (_SelectedItem != value) {
                    _SelectedItem = value;
                    StartCommand.RaiseCanExecuteChanged();
                }
            }
        }

        public AudioPageViewModel() {
            InitListLanguages();
            AzureTranscription = new AzureTranscriptionService();
            DialogHelper = new DialogHelper();
            FolderHelper = new FolderHelper();
            AudioHelper = new AudioHelper();
            CanShow = Visibility.Hidden;
            PickFileCommad = new Command(PickFileAction);
            StartCommand = new Command(StartAction, CanStartAction);
        }

        private bool CanStartAction(object arg) {
            if (string.IsNullOrEmpty(SelectedItem) ||
                string.IsNullOrEmpty(FilePath) ||
                IsWorking == true) {
                return false;
            }
            return true;
        }

        private async void StartAction(object obj) {

            var FileWithoutExtension = Path.GetFileNameWithoutExtension
                (FilePath);

            var AudioPath = FolderHelper.CreateFolder(ConstantsHelpers.AUDIO);

            var DocumentPath = FolderHelper.CreateFolder();

            var AudioFileNamePath = Path.Combine(AudioPath, $"{FileWithoutExtension}{ConstantsHelpers.WAV}");

            var ConvertedAudioPath = AudioHelper.Converter(FilePath!, AudioFileNamePath);

            var DocumentName = Path.Combine(DocumentPath, $"{FileWithoutExtension}{ConstantsHelpers.DOCX}");

            IsWorking = true;

            StartCommand.RaiseCanExecuteChanged();

            await AzureTranscription.ConvertToTextAsync(ConvertedAudioPath,
                SelectedItem, DocumentName);

            IsWorking = false;
            StartCommand.RaiseCanExecuteChanged();


        }

        private void PickFileAction() {
            var FullPath = DialogHelper.GetFilePath(ConstantsHelpers.AUDIO);
            FilePath = FullPath;

            StartCommand?.RaiseCanExecuteChanged();
        }

 public async Task ConvertToTextAsync(
            string FilePath,
            string Language,
            string WordDocName) {

            // Configure speech service

            var config = SpeechConfig.FromSubscription(ConstantsHelpers.AZURE_KEY, ConstantsHelpers.AZURE_REGION);
            config.SpeechRecognitionLanguage = Language;
            // Configure speech recognition

            var taskCompleteionSource = new TaskCompletionSource<int>();

            using var audioConfig = AudioConfig.FromWavFileInput(FilePath);
            using var speechRecognizer = new SpeechRecognizer(config, audioConfig);
            speechRecognizer.Recognizing += SpeechRecognizer_Recognizing;
            speechRecognizer.Recognized += SpeechRecognizer_Recognized;
            speechRecognizer.SessionStarted += SpeechRecognizer_SessionStarted;
            speechRecognizer.SessionStopped += SpeechRecognizer_SessionStopped;

            await speechRecognizer.StartContinuousRecognitionAsync().ConfigureAwait(false);

            Task.WaitAny(new[] { taskCompleteionSource.Task });

            await speechRecognizer.StopContinuousRecognitionAsync().ConfigureAwait(false);
        }

        private void SpeechRecognizer_SessionStopped(object? sender, SessionEventArgs e) {

            Debug.WriteLine("Stepped");
            var sb = new StringBuilder();

            foreach (var item in Letters) {
                sb.Append(item);
            }
        }

        private void SpeechRecognizer_SessionStarted(object? sender, SessionEventArgs e) {

            Debug.WriteLine("Started");
        }
        private void SpeechRecognizer_Recognized(object? sender, SpeechRecognitionEventArgs e) {
            if (e.Result.Reason == ResultReason.RecognizedSpeech) {
                foreach (var item in e.Result.Text) {
                    Letters.Add(item);
                }
            }
        }

        private void SpeechRecognizer_Recognizing(object? sender, SpeechRecognitionEventArgs e) {

            Debug.WriteLine(e.Result.Text);
        }
    }

当我开始工作时,我执行这段代码

非常感谢

【问题讨论】:

  • Task.WaitTask.WaitAny 将引入潜在的死锁并强制同步执行。您应该始终使用await 来等待任务完成。等效的异步 sn-p 将是:await Task.WhenAny。一旦等待的任务返回,您可以设置一个标志,该标志由绑定到 Button 的 ICommand 的 CanExecute 委托检查。如果 CanExecute 返回false,则 Button 将自行禁用。
  • 你能提供一个sn-p的代码吗
  • 你没有提供足够的代码来给你一个例子。只需引入一个私有 bool 属性。然后等待 ConvertToTextAsync。然后,当 await 继续时,将此属性设置为 false。让 ICommand 的 CanExecute 委托检查此属性。
  • 还要确保您的 CanStartAction 返回正确的值。
  • TaskCompletionSource 有什么用?你不使用它。

标签: c# wpf task


【解决方案1】:

如果以下重构没有帮助,请调试您的程序:

  • 检查CanStartAction 是否被实际调用并返回预期结果。
  • 可能异步方法返回的速度太快,您的眼睛无法看到按钮被禁用。修改你的代码如下测试:
await AzureTranscription.ConvertToTextAsync(ConvertedAudioPath,
                SelectedItem, DocumentName);
await Task.Delay(TimeSpan.FromSeconds(5));

通常,将RaiseCanExecuteChanged 请求移至相关的属性设置器以保持代码干净。


private bool isBusy;
private bool IsBusy 
{ 
  get => this.isBusy; 
  set
  {
    this.isBusy = value;
    this.StartCommand.RaiseCanExecuteChanged();
  }
}

private bool CanStartAction(object arg) 
{
  return !string.IsNullOrEmpty(SelectedItem) &&
    !string.IsNullOrEmpty(FilePath) &&
    !this.IsBusy
}

private async void StartAction(object obj) 
{ 
  this.IsBusy = true;

  var fileWithoutExtension = Path.GetFileNameWithoutExtension
                (FilePath);
  var audioPath = FolderHelper.CreateFolder(ConstantsHelpers.AUDIO);
  var documentPath = FolderHelper.CreateFolder();
  var audioFileNamePath = Path.Combine(audioPath, $"{FileWithoutExtension}{ConstantsHelpers.WAV}");
  var convertedAudioPath = AudioHelper.Converter(FilePath!, audioFileNamePath);
  var documentName = Path.Combine(documentPath, $"{fileWithoutExtension}{ConstantsHelpers.DOCX}");

  await AzureTranscription.ConvertToTextAsync(convertedAudioPath,
                this.SelectedItem, documentName);

  this.IsBusy = false;
}

public async Task ConvertToTextAsync(string FilePath,
  string Language,
  string WordDocName) 
{
  ...
  
  // Using Task.Wait, Task.WaitAny and Task.WaitAll will execute a Task synchronously and introduces a potential deadlock.
  // To avoid this, always await a Task and use Task.WhenAny and Task.WhenAll instead
  await Task.WhenAny(new[] { taskCompleteionSource.Task });
  
  // Or because you only have to wait for a single Task write
  await taskCompleteionSource.Task;

  ...
}

C# Naming guidelines

【讨论】:

  • 谢谢,但是按钮没有启用
  • 对不起,它工作正常,我需要弄清楚为什么我的 Azure 方法不起作用
  • 我可以问我做错了什么,为什么投反对票
  • 对不起,我没有对你的帖子投反对票。我会请您发布一个与您的 Azure API 调用相关的新问题。它与这个问题无关。
  • 通常,在使用 Azure 或 Google 服务等任何服务时,请确保您的应用程序经过了正确的身份验证。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-03
  • 1970-01-01
  • 1970-01-01
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多