C#WPF程序按钮单击运行任务,直到另一个按钮单击停止或直到取消令牌有效
我正在创建一个WPF应用程序,其中我希望有一个全局bool,我假设,在第一次单击按钮时,我会将此bool设置为true,并希望它运行一个任务(连续调用API方法),直到我再次单击按钮,它停止它。最好的方法是什么C#WPF程序按钮单击运行任务,直到另一个按钮单击停止或直到取消令牌有效,c#,wpf,multithreading,C#,Wpf,Multithreading,我正在创建一个WPF应用程序,其中我希望有一个全局bool,我假设,在第一次单击按钮时,我会将此bool设置为true,并希望它运行一个任务(连续调用API方法),直到我再次单击按钮,它停止它。最好的方法是什么 private bool running = false; private async void BtnTrade1_Buy_Click(object sender, RoutedEventArgs e) { if (!running)
private bool running = false;
private async void BtnTrade1_Buy_Click(object sender, RoutedEventArgs e)
{
if (!running)
{
running = true;
}
else
running = false;
if (running)
{
RunningNrunnin(running);
//tradeClient.GetTradeHistory();
}
}
public void RunningNrunnin(bool running)
{
if (running)
{
Task task = new Task(() =>
{
while (running)
{
GetTradeHistory();
Thread.Sleep(2000);
}
});
task.Start();
}
}
添加到下面
我想反复调用一个方法,直到用户在后台的线程上创建一个取消请求。我现在有它,所以我可以调用一个操作(计数器)并每秒更新GUI,但当我尝试使用方法调用执行同样的操作时,它只执行一次
// Here is the method I want to call continously until canceled
private async void HistoryTest()
{
cancellationToken = new CancellationTokenSource();
task = Task.Factory.StartNew(async () =>
{
while (true)
{
cancellationToken.Token.ThrowIfCancellationRequested();
await Client2.GetHistory();
await Task.Delay(2000);
}
}, cancellationToken.Token);
}
public async Task GetHistory()
{
try
{
var response = await Client.Service.GetDataAsync
(
ProductType.BtcUsd,
5,
1
);
}
catch(Exception)
{
throw;
}
}
我制作了一个小的控制台测试应用程序来测试这一点,因此我必须更改方法签名(静态),并且不能在控制台上使用
按钮单击
。我通过在编程的“按钮点击”之间设置睡眠来模拟按钮点击
这可能会让你开始
private static bool isRunning = false;
private static int clickCounter = 0;
private static int iterationsCounter = 0;
static void Main(string[] args)
{
Console.WriteLine(“Start”);
for(int i = 0; i < 7; i++)
{
BtnTrade1_Buy_Click();
System.Threading.Thread.Sleep(1000);
}
Console.WriteLine(“END”);
}
private static async Task BtnTrade1_Buy_Click()
{
iterationsCounter = 0;
isRunning = !isRunning;
Console.WriteLine($"Ha: {isRunning} {clickCounter++}");
await RunningNrunnin();
}
private static async Task RunningNrunnin()
{
await Task.Run(() => Runit());
}
private static void Runit()
{
while (isRunning)
{
GetTradeHistory();
System.Threading.Thread.Sleep(100);
}
}
private static void GetTradeHistory()
{
Console.WriteLine($"Hello Test {iterationsCounter++}");
}
private static bool isRunning=false;
私有静态int clickCounter=0;
私有静态int迭代计数器=0;
静态void Main(字符串[]参数)
{
控制台写入线(“开始”);
对于(int i=0;i<7;i++)
{
BtnTrade1_购买_点击();
系统线程线程睡眠(1000);
}
控制台。写入线(“结束”);
}
私有静态异步任务BtnTrade1\u购买\u单击()
{
迭代计数器=0;
isRunning=!isRunning;
WriteLine($“Ha:{isRunning}{clickCounter++}”);
等待运行n运行();
}
私有静态异步任务RunningNrunnin()
{
等待任务。运行(()=>Runit());
}
私有静态void Runit()
{
同时(正在运行)
{
GetTradeHistory();
系统线程线程睡眠(100);
}
}
私有静态无效GetTradeHistory()
{
WriteLine($“Hello Test{IterationCounter++}”);
}
当然,您不需要所有的计数器和Console.WriteLine()
之类的东西。他们在那里让你想象正在发生的事情
如果您需要更多信息,请告诉我。除了切换
isRunning
字段外,您不需要在BtnTrade1\u Buy\u单击事件处理程序中执行任何其他操作:
private bool _isRunning;
private void BtnTrade1_Buy_Click(object sender, RoutedEventArgs e)
{
_isRunning = !_isRunning;
}
在循环中获取交易历史的任务
,只需启动一次。您可以在窗口\u Loaded
事件中启动它。将任务
存储在私有字段中是一个好主意,以防您决定在某个时候等待它,但如果您正在处理任务内部的异常,则不必这样做
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_ = StartTradeHistoryLoopAsync(); // Fire and forget
}
private async Task StartTradeHistoryLoopAsync()
{
while (true)
{
var delayTask = Task.Delay(2000);
if (_isRunning)
{
try
{
await Task.Run(() => GetTradeHistory()); // Run in the ThreadPool
//GetTradeHistory(); // Alternative: Run in the UI thread
}
catch (Exception ex)
{
// Handle the exception
}
}
await delayTask;
}
}
当窗口关闭时,不要忘记停止任务
private void Window_Closed(object sender, EventArgs e)
{
_isRunning = false;
}
这将停止对GetTradeHistory()
的调用,但不会停止循环。您可能需要再添加一个privatebool
字段来控制循环本身:
while (_alive) // Instead of while (true)
当我调试我的程序时,它是否像你的代码一样执行了一次,并使GUI返回,它不会继续执行…@Bigbear你是否尝试过在没有附加调试程序的情况下运行程序?使用Ctrl+F5。那么一个简单的问题,您会推荐每1-2秒进行一次这样的方法调用,还是推荐WebSocket进行连续数据调用?(交易订单),只要我使用Task.Run(),它是否在后台运行?所以我可以继续使用主GUI进行其他调用?@Bigbear我还没有使用WebSockets,所以我无法给出明智的建议。我想WebSocket更轻,但它可能更复杂。无论如何,不要引用我的话。:-)