gpt4 book ai didi

c# - 告诉任务等到计时器停止

转载 作者:行者123 更新时间:2023-11-30 17:04:02 24 4
gpt4 key购买 nike

解释和背景:对不起,如果这个问题很糟糕,但我正在努力解决任务问题。我目前有一组类,这些类将对其构造函数进行控制,并允许我自动执行用户交互(输入文本框、单击按钮等)。

其中一个例子是我的名为 TextboxTester 的类。这是我如何引入文本框的片段:

public class TextboxTester
{
private int _currentTextLength = 0;
private string _text;
private TextBox _textBox;
private Timer timer;

#region Constructor
public TextboxTester(TextBox TextBox)
{
_textBox = TextBox;
}
#endregion

我希望能够按顺序将操作(任务)链接在一起 - 一个接一个,这样我就可以自动执行一系列用户输入事件。我阅读并了解了 TPL 任务,并决定试一试。

我创建了我的 TextboxTester 类和我的 ButtonTester 类,并传入了控件。我希望能够在文本框中输入内容,然后单击按钮 - 所以我称之为:

Task.Factory.StartNew(() => txtTester.WriteText("Hello World")).Wait();
Task.Factory.StartNew(() => btnTester.Click(1));

根据我对 Task.Factory 调用的了解,这就是我想要做的 - 执行第一个操作,等待它完成 - 然后执行下一个。问题是 TextboxTester.WriteText() 使用计时器模拟输入到 TextBox 中(每秒 1 个字符):

public void WriteText(string Text)
{
if (timer == null)
{
State.Working = true;
timer = new Timer();

try
{
_text = Text;
timer.Elapsed += new ElapsedEventHandler(timer_ElapsedWrite);
timer.Interval = 1000;
timer.Enabled = true;
timer.Start();
}
catch
{
MessageBox.Show("WriteText timer could not be started.");
}
}
}
void timer_ElapsedWrite(object sender, ElapsedEventArgs e)
{
_textBox.Dispatcher.BeginInvoke(new Action(() =>
{
TextBoxAutomationPeer peer = new TextBoxAutomationPeer(_textBox);
IValueProvider valueProvider = peer.GetPattern(PatternInterface.Value) as IValueProvider;
valueProvider.SetValue(_text.Substring(0, _currentTextLength));

if (_currentTextLength == _text.Length)
{
timer.Stop();
State.Working = false;
timer = null;
return;
}

_currentTextLength++;

}));
}

**在 elapsed 事件中调用 _textBox.Dispatcher 是为了防止出现“线程已经拥有此对象”消息。

最后的问题是: Task.Factory.StartNew() 调用似乎没有考虑仍在发生的 time_elapsed 事件。我希望能够在任务认为“WriteText”完成之前完成事件。

和问题:有没有办法告诉任务能够考虑这些类型的事情?我不了解任务吗?

编辑 - 我正在使用 3.5 和 TPL 的 3.5 实现

最佳答案

现在您无法从使用任务中获得任何好处。使 WriteText 成为异步方法可以使事情变得容易得多:

public async Task WriteText(string text)
{
TextBoxAutomationPeer peer = new TextBoxAutomationPeer(_textBox);
IValueProvider valueProvider = peer.GetPattern(PatternInterface.Value) as IValueProvider;
for(int i = 1; i < text.Length; ++i)
{
await Task.Delay(1000); // no need for timer
valueProvider.SetValue(text.Substring(0, i));
}
}

所以你可以写

async void TestMethod()
{
await txtTester.WriteText("Hello World"));
Task.Factory.StartNew(() => btnTester.Click(1)); // probably sould be refactored too
}

编辑

没有 async/await 的版本,对现有代码的改动很小:

public class TextboxTester
{
/* unchanged code */

// unfortunately, there is no non-generic version of this class
// basically it allows us to 'manually' complete Task
private TaskCompletionSource<object> _tcs;

public Task WriteText(string Text)
{
if (timer == null)
{
_tcs = new TaskCompletionSource<object>();
/* unchanged code */
}
return _tcs.Task; // return task which tracks work completion
}

/* unchanged code */
if (_currentTextLength == _text.Length)
{
timer.Stop();
State.Working = false;
timer = null;
_tcs.TrySetResult(null); // notify completion
return;
}
/* unchanged code */
}

现在你可以写了

// well, you could simply make this a blocking method instead
txtTester.WriteText("Hello World").Wait();
btnTester.Click(1);

或更好

txtTester.WriteText("Hello World")
.ContinueWith(t => btnTester.Click(1)); // does not block calling thread

主要思想是以允许报告完成的方式设计异步方法。有 3 种常见模式:

  • 开始/结束方法对(BeginWriteText,它返回 IAsyncResultEndWriteText,它接受 IAsyncResult)
  • 工作完成时调用的事件(public event EventHandler WriteTextCompleted)
  • 基于任务的方法(方法返回Task)

这些方法在 Task-based Asynchronous Pattern 中有详细描述

关于c# - 告诉任务等到计时器停止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18008852/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com