3

说明和背景: 对不起,如果这个问题很糟糕,但我正试图围绕任务。我目前有一组类,它们将控制到它们的构造函数中,并允许我自动化用户交互(输入文本框、单击按钮等)。

其中一个例子是我的班级,名为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++;

        }));
    }

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

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

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

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

4

1 回答 1

2

现在,您没有从使用任务中获得任何好处。制作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

这些方法在基于任务的异步模式中有很好的描述

于 2013-08-02T05:14:57.647 回答