Это старый пост, но я трачу 2 дня на достижение результата, который я хочу представить здесь (с "контекстом" и полным, но упрощенным кодом)
Ответ @ Joshua работал для меня (наконец, когда я установил true для .ConfigureAwait (true), см. Первый пример кода). Возможно, мне удалось написать меньше строк на основе длинной статьи MSDN Threading Model , которую мне все еще нужно прочитать еще раз.
Мой контекст - WPF (базовый MVVM), и я должен выбрать файл для записи некоторой резервной копии .CSV (из сетки данных). Мне нужно, чтобы функция (член) ChooseFileFromExtension()
была асинхронной с неблокирующим FileDialog
class MainWindowExportToExcelCSV : ICommand
{
...
public async void Execute(object parameter)
{
var usr_ctrl = parameter as UserControl;
MyFileDialog fd = new MyFileDialog();
const bool WhenIComeBackIStillNeedToAccessUIObjectAndThusINeedToRetrieveMyOriginalUIContext = true;
string filename = await fd.ChooseFileFromExtension("CSV files (*.csv)|*.csv|All files (*.*)|*.*").ConfigureAwait(
WhenIComeBackIStillNeedToAccessUIObjectAndThusINeedToRetrieveMyOriginalUIContext);
Visual visual = (Visual)usr_ctrl.Content;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
{
//look for datagrid element
}
}
}
и код для класса MyFileDialog
using Microsoft.Win32;
...
class MyFileDialog
{
//https://msdn.microsoft.com/en-us/library/ms741870(v=vs.110).aspx
//Article on Threading Model
private delegate void OneArgStrDelegate(string str);
private void MyExternalDialog(string extensions)
{
SaveFileDialog fd = new SaveFileDialog();
fd.Filter = extensions;
fd.ShowDialog();
tcs.SetResult(fd.FileName);
}
private TaskCompletionSource<string> tcs;
public Task<string> ChooseFileFromExtension(string file_ext)
{
//Cf Puppet Task in Async in C#5.0 by Alex Davies
tcs = new TaskCompletionSource<string>();
OneArgStrDelegate fetcher = new OneArgStrDelegate(this.MyExternalDialog);
fetcher.BeginInvoke(file_ext, null, null);
return tcs.Task;
}
}
fetcher.BeginInvoke()
запускает (асинхронно) SaveFileDialog
ShowDialog()
в другом потоке, так что основной поток / окно пользовательского интерфейса (... ++) не блокируются и не отключаются, как это было бы с простым прямым позвоните по номеру ShowDialog()
. TaskCompletionSource<string> tcs
не является объектом пользовательского интерфейса WPF, поэтому его доступ к другому «отдельному» потоку в порядке.
Это все еще поле, которое мне нужно изучить дальше. Я чувствую, что нет «окончательной» документации / книги по этому вопросу (может быть, стоит еще раз взглянуть на книги, подобные книге Стивена Клири). Этот код должен быть улучшен, по крайней мере, с темой, описанной в c-sharp-asynchronous-call-без-endinvoke
Работает с FileDialog пространства имен Microsoft.Win32