Async wait until form is loaded to continue - c#

I am trying to get my form to wait until a particular part of my _Load method is finished before continuing. I have a few methods that are async, but I cannot figure out why I am not able to get the code to wait until fakeClickCheckUpdate is finished before continuing. Here are the main methods involved:
public myForm(string args)
{
InitializeComponent();
Load += myForm_Load;
}
private void myForm_Load(object s, EventArgs e)
{
this.fakeClickCheckUpdate();
loadFinished = true;
if (this.needsUpdate == true)
{
Console.WriteLine("Needs update...");
}
else
{
Console.WriteLine("update is false");
}
}
public void fakeClickCheckUpdate()
{
this.checkUpdateButton.PerformClick();
}
private async void checkUpdateButton_Click(object sender, EventArgs e)
{
await startDownload(versionLink, versionSaveTo);
await checkVersion();
Console.WriteLine(needsUpdate);
}
private async Task checkVersion()
{
string currVersion;
string newVersion;
using (StreamReader sr = new StreamReader(currVersionTxt))
{
currVersion = sr.ReadToEnd();
}
using (StreamReader nr = new StreamReader(versionSaveTo))
{
newVersion = nr.ReadToEnd();
}
if (!newVersion.Equals(currVersion, StringComparison.InvariantCultureIgnoreCase))
{
this.BeginInvoke((MethodInvoker)delegate
{
progressLabel.Text = "New version available! Please select 'Force Download'";
});
this.needsUpdate = true;
}
else
{
this.BeginInvoke((MethodInvoker)delegate
{
progressLabel.Text = "Your version is up-to-date. No need to update.";
});
this.needsUpdate = false;
}
}
Basically, I want it to check the current version with checkVersion and finish that before it tries to continue past loadFinished = true inside of myForm_Load. I have checkVersion set as an async Task so that the button click can use await on it. Is there any way to get the functionality I need with this code?

First, move your code out of your perform click action.
private async void checkUpdateButton_Click(object sender, EventArgs e)
{
await CheckForUpdate();
}
private async Task CheckForUpdate()
{
await startDownload(versionLink, versionSaveTo);
await checkVersion();
Console.WriteLine(needsUpdate);
}
You can then call that same function in your OnLoad.
private async void myForm_Load(object s, EventArgs e)
{
await CheckForUpdate();
loadFinished = true;
if (this.needsUpdate == true)
{
Console.WriteLine("Needs update...");
}
else
{
Console.WriteLine("update is false");
}
}

Related

Azure cognitive stops immediately after I start

I am trying to transcribe a WAV file and return the text, but it stopped immediately when I start working
I have a button, that when I click it, will call this method, and it supposedly returns me the text of the wav file, but as you can see from the code, I have a Dbug.WriteLine in the start and the stop, and it will print stop immediately
public List<char> Letters { get; set; }
public StringBuilder Builder { get; set; }
public AzureTranscriptionService() {
Letters = new List<char>();
Builder = new StringBuilder();
}
public async Task<string> ConvertToTextAsync(
string FilePath,
string Language,
string WordDocName) {
//Configure speech service
var config = SpeechConfig.FromSubscription
(ConstantsHelpers.AZURE_KEY,
ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
config.SpeechRecognitionLanguage = Language;
//Configure speech recognition
var stopRecognition = new TaskCompletionSource<string>();
using var audioConfig = AudioConfig.FromWavFileInput
(FilePath);
{
using var speechRecognizer =
new SpeechRecognizer(config, audioConfig);
speechRecognizer.Recognized += (sender, e) => {
if (e.Result.Reason == ResultReason.RecognizedSpeech) {
foreach (var c in e.Result.Text) {
Letters.Add(c);
}
}
};
speechRecognizer.SessionStarted += (sender, e) => {
Debug.WriteLine("------> Started");
};
speechRecognizer.SessionStopped += (sender, e) => {
Debug.WriteLine("Stop");
foreach (var item in Letters) {
Builder.Append(item);
}
};
speechRecognizer.Recognizing += (sender, e) => {
Debug.WriteLine(e.Result.Text);
stopRecognition.TrySetResult(0);
};
await speechRecognizer.StartContinuousRecognitionAsync();
// Waits for completion. Use Task.WaitAny to keep the task rooted.
await Task.WhenAny(new[] { stopRecognition.Task });
return Builder.ToString();
}
}
}
}
Update
I tried to change the code to this
private TaskCompletionSource<string>? SpeechRecognitionCompletionSource { get; set; }
private StringBuilder? RecognizedSpeechTextBuilder { get; set; } = new StringBuilder();
private SpeechRecognizer? SpeechRecognizer { get; set; }
public async Task<string> ConvertToTextAsync(string filePath,
string language,
string wordDocName) {
// Configure speech service
var config = SpeechConfig.FromSubscription(ConstantsHelpers.AZURE_KEY, ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
config.SpeechRecognitionLanguage = language;
// Configure speech recognition
this.SpeechRecognitionCompletionSource = new TaskCompletionSource<string>();
using var audioConfig = AudioConfig.FromWavFileInput(filePath);
using (SpeechRecognizer = new SpeechRecognizer(config, audioConfig)) {
SpeechRecognizer.SessionStarted += OnSessionStarted!;
SpeechRecognizer.SessionStopped += OnSessionStopped!;
SpeechRecognizer.Recognizing += OnRecognizing!;
SpeechRecognizer.Recognized += OnRecognized!;
await this.SpeechRecognizer.StartContinuousRecognitionAsync();
// Wait for the 'SpeechRecognizer.StopContinuousRecognitionAsync' call
// before returning the result string.
// In this case, 'SpeechRecognizer.StopContinuousRecognitionAsync'
// is called from a Button.Click event handler.
return await SpeechRecognitionCompletionSource.Task;
}
}
// Stop speech recognition when the user clicks a button
private async void OnStopButtonClicked(object sender, RoutedEventArgs e) {
await SpeechRecognizer!.StopContinuousRecognitionAsync();
}
private void OnSessionStarted(object sender, SessionEventArgs e) {
Debug.WriteLine("------> Started");
}
private void OnSessionStopped(object sender, SessionEventArgs e) {
Debug.WriteLine("Stop");
SpeechRecognitionCompletionSource!.TrySetResult(RecognizedSpeechTextBuilder!.ToString());
}
private void OnRecognizing(object sender, SpeechRecognitionEventArgs e) {
Debug.WriteLine(e.Result.Text);
}
private void OnRecognized(object sender, SpeechRecognitionEventArgs e) {
if (e.Result.Reason != ResultReason.RecognizedSpeech) {
return;
}
foreach (var speechText in e.Result.Text) {
this.RecognizedSpeechTextBuilder!.Append(speechText);
}
}
}
}
and then I call this method in here'
private async void StartAction(object obj) {
IsBusy = true;
CanShow = Visibility.Visible;
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}");
var res = await AzureTranscription.ConvertToTextAsync(ConvertedAudioPath,
SelectedItem, DocumentName);
IsBusy = false;
StartCommand.RaiseCanExecuteChanged();
CanShow = Visibility.Hidden;
}
Update
I manage to get it working, but I need to return the text to my MainViewModel
public async Task ConvertToTextAsync(string FilePath, string FileName) {
List<char> Characers = new();
StringBuilder builder = new();
//Configure speech service
var config = SpeechConfig.FromSubscription
(ConstantsHelpers.AZURE_KEY, ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
//Configure speech recognition
var taskCompleteionSource = new TaskCompletionSource<int>();
using var audioConfig = AudioConfig.FromWavFileInput(FilePath);
if (!string.IsNullOrEmpty(FileName)) {
using var speechRecognizer = new SpeechRecognizer(config, audioConfig);
speechRecognizer.Recognized += (sender, e) => {
if (e.Result.Reason == ResultReason.RecognizedSpeech) {
foreach (var item in e.Result.Text) {
Characers.Add(item);
}
}
};
speechRecognizer.SessionStarted += (sender, e) => {
Debug.WriteLine("--------> started");
};
speechRecognizer.SessionStopped += (sender, e) => {
Debug.WriteLine("-----------> stooped");
foreach (var item in Characers) {
builder.Append(item);
}
Debug.WriteLine(builder.ToString());
};
await speechRecognizer.StartContinuousRecognitionAsync()
.ConfigureAwait(false);
Task.WaitAny(new[] { taskCompleteionSource.Task });
await speechRecognizer.StopContinuousRecognitionAsync()
.ConfigureAwait(false);
}
return builder.ToString();
}
}
}
I seems like you are returning from the ConvertToTextAsync method prematurely. This is because you are transitioning the TaskCompletionSource too early. As a consequence you leave the method and therefore the using scope of the SpeechRecognizer, which as a result will stop the continuous speech recognition.
The idea is to complete the TaskCompletionSource not before the SpeechRecognizer has stopped (by calling the SpeechRecognizer.StopContinuousRecognitionAsync method). You can achieve this by calling TaskCompletionSource.TrySetResult from the SpeechRecognizer.SessionStopped event handler:
private TaskCompletionSource<string> SpeechRecognitionCompletionSource { get; set; }
private StringBuilder RecognizedSpeechTextBuilder { get; set; }
private SpeechRecognizer SpeechRecognizer { get; set; }
public async Task<string> ConvertToTextAsync(string filePath,
string language,
string wordDocName)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException(filePath);
}
// Configure speech service
var config = SpeechConfig.FromSubscription(ConstantsHelpers.AZURE_KEY, ConstantsHelpers.AZURE_REGION);
config.EnableDictation();
config.SpeechRecognitionLanguage = language;
// Configure speech recognition
this.SpeechRecognitionCompletionSource = new TaskCompletionSource<string>();
using var audioConfig = AudioConfig.FromWavFileInput(filePath);
using (this.SpeechRecognizer = new SpeechRecognizer(config, audioConfig))
{
this.SpeechRecognizer.SessionStarted += OnSessionStarted;
this.SpeechRecognizer.SessionStopped += OnSessionStopped;
this.SpeechRecognizer.Recognizing += OnRecognizing;
this.SpeechRecognizer.Recognized += OnRecognized;
this.SpeechRecognizer.Recognized += OnCanceled;
await this.SpeechRecognizer.StartContinuousRecognitionAsync();
// Wait for the 'SpeechRecognizer.StopContinuousRecognitionAsync' call
// before returning the result string.
// In this case, 'SpeechRecognizer.StopContinuousRecognitionAsync'
// is called from a Button.Click event handler.
return await this.SpeechRecognitionCompletionSource.Task;
}
}
// Stop speech recognition when the user clicks a button
private async void OnStopButtonClicked(object sender, RoutedEventArgs e)
{
await this.SpeechRecognizer.StopContinuousRecognitionAsync();
}
private void OnSessionStarted(object sender, SessionEventArgs e)
{
Debug.WriteLine("------> Started");
}
private void OnSessionStopped(object sender, SessionEventArgs e)
{
Debug.WriteLine("Stop");
this.SpeechRecognitionCompletionSource.TrySetResult(this.RecognizedSpeechTextBuilder.ToString());
}
private void OnRecognizing(object sender, SpeechRecognitionEventArgs e)
{
Debug.WriteLine(e.Result.Text);
}
private void OnRecognized(object sender, SpeechRecognitionEventArgs e)
{
if (e.Result.Reason != ResultReason.RecognizedSpeech)
{
return;
}
foreach (string speechText in e.Result.Text)
{
this.RecognizedSpeechTextBuilder.Append(speechText);
}
}
private void OnCanceled(object sender, SpeechRecognitionCanceledEventArgs e)
{
if(e.Reason == CancellationReason.EndOfStream)
{
await this.SpeechRecognizer.StopContinuousRecognitionAsync();
}
}

Updating Winforms Label with Timer and Thread, stock app

Gist of it has probably been asked before, but I'm completely lost so I'm looking for some personal guidance. Been trying to make a stock tracker app for funsies using WinForms and the Yahoo API. Trying to get it so you can input a tracker symbol and it will make a new Label that will keep updating itself every so often. However, it keeps giving me error messages about "Cross-thread operation not valid". I've tried to do some googling, but yeah, completely lost. Here is most of the code, hope you guys can make some sense of it.
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using YahooFinanceApi;
namespace stockpoging4
{
public partial class Form1 : Form
{
public Form1()
{
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo("en-US");
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (Prompt prompt = new Prompt("Enter the ticker symbol", "Add ticker"))
{
string result = prompt.Result;
result = result.ToUpper();
if (!string.IsNullOrEmpty(result))
{
do_Things(result);
}
}
}
public async Task<string> getStockPrices(string symbol)
{
try
{
var securities = await Yahoo.Symbols(symbol).Fields(Field.RegularMarketPrice).QueryAsync();
var aapl = securities[symbol];
var price = aapl[Field.RegularMarketPrice];
return symbol + " $" + price;
}
catch
{
return "404";
}
}
public async void do_Things(string result)
{
string price;
Label label = null;
if (label == null)
{
price = await getStockPrices(result);
label = new Label() { Name = result, Text = result + " $" + price };
flowLayoutPanel2.Controls.Add(label);
}
else
{
Thread testThread = new Thread(async delegate ()
{
uiLockingTask();
price = await getStockPrices(result);
label.Text = result + " $" + price;
label.Update();
});
}
System.Timers.Timer timer = new System.Timers.Timer(10000);
timer.Start();
timer.Elapsed += do_Things(results);
}
private void uiLockingTask() {
Thread.Sleep(5000);
}
}
}
Let me point out several things in your implementation.
You subscribe to timer.Elapsed after timer.Start that might be invalid in case of a short-timer interval
The event handler is called in background that's why you continuously get "Cross-thread operation not valid". UI components should be dispatched correctly from background threads, for example, by calling flowLayoutPanel2.BeginInvoke(new Action(() => flowLayoutPanel2.Controls.Add(label))); and label.BeginInvoke(new Action(label.Update)). This change already would fix your exception.
Despite the fact that I would implement this functionality in a different way, here I post slightly changed code that just does exactly what you need with some tweaks.
public partial class Form1 : Form
{
Task _runningTask;
CancellationTokenSource _cancellationToken;
public Form1()
{
System.Globalization.CultureInfo.DefaultThreadCurrentUICulture = System.Globalization.CultureInfo.GetCultureInfo("en-US");
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (Prompt prompt = new Prompt("Enter the ticker symbol", "Add ticker"))
{
string result = prompt.Result;
result = result.ToUpper();
if (!string.IsNullOrEmpty(result))
{
do_Things(result);
_cancellationToken = new CancellationTokenSource();
_runningTask = StartTimer(() => do_Things(result), _cancellationToken);
}
}
}
private void onCancelClick()
{
_cancellationToken.Cancel();
}
public async Task<string> getStockPrices(string symbol)
{
try
{
var securities = await Yahoo.Symbols(symbol).Fields(Field.RegularMarketPrice).QueryAsync();
var aapl = securities[symbol];
var price = aapl[Field.RegularMarketPrice];
return symbol + " $" + price;
}
catch
{
return "404";
}
}
private async Task StartTimer(Action action, CancellationTokenSource cancellationTokenSource)
{
try
{
while (!cancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(1000, cancellationTokenSource.Token);
action();
}
}
catch (OperationCanceledException) { }
}
public async void do_Things(string result)
{
var price = await getStockPrices(result);
var label = new Label() { Name = result, Text = result + " $" + price };
flowLayoutPanel2.BeginInvoke(new Action(() => flowLayoutPanel2.Controls.Add(label)));
}
}
A much easier way is using async these days.
Here is a class which triggers an Action every interval:
public class UITimer : IDisposable
{
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
// use a private function which returns a task
private async Task Innerloop(TimeSpan interval, Action<UITimer> action)
{
try
{
while (!_cancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(interval, _cancellationTokenSource.Token);
action(this);
}
}
catch (OperationCanceledException) { }
}
// the constructor calls the private StartTimer, (the first part will run synchroniously, until the away delay)
public UITimer(TimeSpan interval, Action<UITimer> action) =>
_ = Innerloop(interval, action);
// make sure the while loop will stop.
public void Dispose() =>
_cancellationTokenSource?.Cancel();
}
If you work with dotnet 3.0 or higher, you can use the IAsyncDisposable. With this you're able to await the DisposeAsync method, so you can await the _timerTask to be finished.
And I created a new form with this as code behind:
public partial class Form1 : Form
{
private readonly UITimer _uiTimer;
private int _counter;
public Form1()
{
InitializeComponent();
// setup the time and pass the callback action
_uiTimer = new UITimer(TimeSpan.FromSeconds(1), Update);
}
// the orgin timer is passed as parameter.
private void Update(UITimer timer)
{
// do your thing on the UI thread.
_counter++;
label1.Text= _counter.ToString();
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
// make sure the time (whileloop) is stopped.
_uiTimer.Dispose();
}
}
The advantage is, that the callback runs on the UI thread but doesn't block it. The await Task.Delay(..) is using a Timer in the background, but posts the rest of the method/statemachine on the UI thread (because the UI thread has a SynchronizaionContext)
Easy but does the trick ;-)

Wait users click on popup with Rg.Plugins.Popup

I show a pop up and I have to wait user's choice to put something in an entry control, the problem is that the if statment where I decide what goes as text in entry is executing at the same time as the popup shows.
I tried by making the method await but not working, here's what I have.
Donesn't matter by now the if() statement,I was just trying
This is my popup class (I want to wait until one of the buttons is clicked):
public partial class PopupElegirRFC : PopupPage
{
string sEmisor = "";
string sReceptor = "";
public PopupElegirRFC (string emisor, string receptor)
{
InitializeComponent ();
lblREmisor.Text = "Emisor: " + emisor;
lblRReceptor.Text = "Receptor: " + receptor;
sEmisor = emisor;
sReceptor = receptor;
}
private void BtnEmisor_Clicked(object sender, EventArgs e)
{
PopupNavigation.Instance.PopAllAsync();
VGlobales.sRFSeleccionado = sEmisor;
}
private void BtnReceptor_Clicked(object sender, EventArgs e)
{
PopupNavigation.Instance.PopAllAsync();
VGlobales.sRFSeleccionado = sReceptor;
}
}
This is the code where I want to wait for users choice:
case 2:
await PopupNavigation.Instance.PushAsync(new Popups.PopupElegirRFC(list[0], list[1]));
if (VGlobales.sRFSeleccionado == list[1])
{
RFCavalidar.Text = list[1];
VGlobales.sRFSeleccionado = "";
}
else
{
RFCavalidar.Text = list[0];
VGlobales.sRFSeleccionado = "";
}
break;
The code executes, but it goes directly to the if(), not waiting the user's choice
I would like to the popup to wait until some of both buttons in it is clicked. so I can make the if() validation
It's an old question but my answer can help someone.
Add TaskCompletionSource and wait for return.
Popup class:
public partial class PopupElegirRFC : PopupPage
{
private TaskCompletionSource<string> taskCompletionSource;
public Task<string> PopupClosedTask { get { return taskCompletionSource.Task; } }
string sEmisor = "";
string sReceptor = "";
public PopupElegirRFC (string emisor, string receptor)
{
InitializeComponent();
lblREmisor.Text = "Emisor: " + emisor;
lblRReceptor.Text = "Receptor: " + receptor;
sEmisor = emisor;
sReceptor = receptor;
}
protected override void OnAppearing ()
{
base.OnAppearing();
taskCompletionSource = new TaskCompletionSource<string>();
}
private void BtnEmisor_Clicked (object sender, EventArgs e)
{
taskCompletionSource.SetResult(sEmisor);
PopupNavigation.Instance.PopAllAsync();
}
private void BtnReceptor_Clicked (object sender, EventArgs e)
{
taskCompletionSource.SetResult(sReceptor);
PopupNavigation.Instance.PopAllAsync();
}
}
Code where you want to wait:
var popupElegirRFC = new Popups.PopupElegirRFC(list[0], list[1]);
await PopupNavigation.Instance.PushAsync(popupElegirRFC);
string result = await popupElegirRFC.PopupClosedTask;
if (result == list[1])
{
RFCavalidar.Text = list[1];
}
else
{
RFCavalidar.Text = list[0];
}
This idea came from the link below:
https://github.com/rotorgames/Rg.Plugins.Popup/issues/116
as jason suggested , you can use MessagingCenter to evaluate whether which button is clicked or not.
In your Button click in popup page
private void BtnEmisor_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send((App)Application.Current,"BtnEmisor_Clicked");
PopupNavigation.Instance.PopAllAsync();
VGlobales.sRFSeleccionado = sEmisor;
}
In your non- Popup page
MessagingCenter.Subscribe((App)Application.Current, "BtnEmisor_Clicked", (sender) =>
{
// Do task on that button click
});

How to show waiting Gif image during form load event

i have one form which is doing some long process on form load event,
So i want to show One Gif image "Please Wait" during form load event.
below is code.
private void frmWaitShow()
{
try
{
frmWaitwithstatus objWait = new frmWaitwithstatus();// this form has Gif Image for Processing
objWait.lblStatus.Text = "Processing Request, Please wait...";
objWait.ShowDialog();
}
catch (Exception ex)
{
Logger.SystemException(ex);
Logger.FTSError(" ERROR :" + ex.Message + "frmTest || frmWaitShow");
}
}
Thread oThread;
private void frmTest_Load(object sender, EventArgs e)
{
try
{
oThread = new Thread(new ThreadStart(frmWaitShow));
oThread.Start();
//Functions for Connection with devices
if (LoadDatafromDB() == false) return;
if (ElectTestLoad() == false) return;
if (PowerOnSelfTest() == false) { return; }
InitiControlsElectTest();
SetSystemMode(SystemMode.ElectricalMode);
oThread.Abort();
}
catch (Exception ex)
{
oThread.Abort();
Logger.SystemException(ex);
}
}
after Thread.start() my debugger go one one step in each thread main and one i created but after it go to below line.
frmWaitwithstatus.cs constructor first line
public frmWaitwithstatus()
it stop execute my Thread and execute all function of main thread once Main Thread execution complete after then only it start execute my thread (which is Gif processing image).
Using the async/await pattern will made this an easy task and every form will work on UI thread:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void Form1_Load(object sender, EventArgs e)
{
// async show loading form dialog
var loadingForm = new LoadingForm();
var loadingDialogTask = this.InvokeAsync(loadingForm.ShowDialog);
// async loading data
var data = await LoadDataAsync();
listBox1.DataSource = data;
loadingForm.Close();
await loadingDialogTask;
}
private async Task<ICollection<string>> LoadDataAsync()
{
// fake work load
await Task.Delay(4000).ConfigureAwait(false);
return Enumerable.Range(1,20000).Select(e => e.ToString()).ToList();
}
}
Needed async extension for the controls:
public static class ControlAsyncExtensions
{
public static Task InvokeAsync(this Control control, Action action)
{
var tcs = new TaskCompletionSource<bool>();
control.BeginInvoke(new Action(() =>
{
try
{
action();
tcs.SetResult(true);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
));
return tcs.Task;
}
public static Task<T> InvokeAsync<T>(this Control control, Func<T> action)
{
var tcs = new TaskCompletionSource<T>();
control.BeginInvoke(new Action(() =>
{
try
{
tcs.SetResult(action());
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}
));
return tcs.Task;
}
}

How to pause or stop "CSharpScript" running?

I'm using Roslyn's scripting API in my application, code snippet as following:
public class ScriptEngine
{
public static string CodeText;
public static event Action<string[]> CompileErrorEvent;
public static async Task<bool> RunScriptAsync(CancellationToken ct)
{
try
{
var scriptResult = await CSharpScript.RunAsync(CodeText, null, new ScriptHost(), null, ct);
return true;
}
catch (Microsoft.CodeAnalysis.Scripting.CompilationErrorException ex)
{
List<string> result = new List<string>();
foreach (var item in ex.Diagnostics)
{
result.Add(item.ToString());
}
if (result.Count > 0)
{
CompileErrorEvent?.Invoke(result.ToArray());
}
return false;
}
catch (Exception ex)
{
IMCP_Base.Dialog.Show.SimpleError("脚本运行", ex.Message, "修改脚本");
return false;
}
}
.......
}
public static CancellationTokenSource ScriptCTS;
private async void btnScriptRun_ItemClick(object sender, ItemClickEventArgs e)
{
ScriptCTS = new CancellationTokenSource();
if (CheckScriptEditorIsNotNull())
{
Script.ScriptEngine.CodeText = ScriptEditor.GetCode();
bool runSuccess = await Script.ScriptEngine.RunScriptAsync(ScriptCTS.Token);
}
}
private void btnScriptStop_ItemClick(object sender, ItemClickEventArgs e)
{
ScriptCTS?.Cancel();
}
CSharpScript.RunAsync method runs well, but when I click ScriptStop button, ScriptCTS?.Cancel() can't cancel running script.
How can I stop or pause a script running?
If you want cancellation points within your scripts, you can use globals, and pass in the CancelationToken, which you can then check in your scripts for cancellation.

Categories