Làm thế nào để tạo một tác vụ (TPL) chạy một chuỗi STA?


75

Sử dụng Chủ đề khá đơn giản

 Thread thread = new Thread(MethodWhichRequiresSTA);
 thread.SetApartmentState(ApartmentState.STA);  

Làm thế nào để hoàn thành điều tương tự bằng cách sử dụng Tác vụ trong ứng dụng WPF? Đây là một số mã:

Task.Factory.StartNew
  (
    () => 
    {return "some Text";}
  )
   .ContinueWith(r => AddControlsToGrid(r.Result));  

Tôi nhận được một lỗi không hợp lệ với

Luồng gọi phải là STA, vì nhiều thành phần giao diện người dùng yêu cầu điều này.

Câu trả lời:


75

Bạn có thể sử dụng Phương thức TaskScheduler.FromCurrentSynchronizationContext để lấy TaskScheduler cho ngữ cảnh đồng bộ hóa hiện tại (là trình điều phối WPF khi bạn đang chạy ứng dụng WPF).

Sau đó, sử dụng quá tải ContinueWith chấp nhận TaskScheduler:

var scheduler = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew(...)
            .ContinueWith(r => AddControlsToGrid(r.Result), scheduler);

10
Chỉ để được rõ ràng; chỉ lambda trong phương thức ContinueWith sẽ chạy với ngữ cảnh thích hợp, không chạy trong lambda tác vụ chính.
dudeNumber

Cảm ơn cho điều này, tôi đã cố gắng TaskScheduler.Current(từ bên trong một xử lý sự kiện nút WinForms), không thể hiểu tại sao nó không hoạt động ...
Benjol

11
Như một điểm cần làm rõ, cũng có một tình trạng quá tải đối với phương thức thể hiện Task.Start () sử dụng TaskScheduler. Chi tiết của câu hỏi làm rõ rằng chúng tôi quan tâm hơn đến trường hợp tiếp tục, nhưng câu hỏi chung hơn về cách chạy một Tác vụ trên một chuỗi STA không chỉ giới hạn trong trường hợp đó. Lúc đầu, tôi đã giả định sai rằng tôi sẽ cần tiếp tục từ một nhiệm vụ "fudge" trống để chạy tác vụ STA mong muốn của mình.
Josh Sutterfield

2
Vì vậy, không nên chỉnh sửa tiêu đề của câu hỏi này để phản ánh tốt hơn ý định của nó?
Mrchief

Hoặc chia nhỏ thành hai. "Làm cách nào để tôi bắt đầu một tác vụ trên một chuỗi STA" và "Làm cách nào để tôi tiếp tục một tác vụ trên một chuỗi STA".
David


0

Dispatcher.Invoke có thể là một giải pháp. ví dụ

    private async Task<bool> MyActionAsync()
    {
        // await for something, then return true or false
    }
    private void StaContinuation(Task<bool> t)
    {
        myCheckBox.IsChecked = t.Result;
    }
    private void MyCaller()
    {
        MyActionAsync().ContinueWith((t) => Dispatcher.Invoke(() => StaContinuation(t)));
    }

Các ContinueWithvà các Dispatcherđược coi là phương pháp tiếp cận cũ sau sự ra đời của async / await. Tôi sẽ tránh sử dụng chúng để phát triển mới (nói chung).
Theodor Zoulias
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.