C # OpenFileDialog Немодально возможно - PullRequest
7 голосов
/ 26 января 2009

Можно ли создать / иметь немодальный .net OpenFileDialog? У меня есть элемент интерфейса в главном диалоговом окне, который всегда должен быть доступен для нажатия пользователем.

Ответы [ 4 ]

6 голосов
/ 24 июля 2009

Вы можете создать поток и разместить его в OpenFileDialog. В примере кода отсутствует какая-либо синхронизация, но он работает.

public partial class Form1 : Form
{
    OFDThread ofdThread;

    public Form1()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
        ofdThread = new OFDThread();
        ofdThread.Show();
    }
}

public class OFDThread
{
    private Thread t;
    private DialogResult result;

    public OFDThread()
    {
        t = new Thread(new ParameterizedThreadStart(ShowOFD));
        t.SetApartmentState(ApartmentState.STA);
    }

    public DialogResult DialogResult { get { return this.result; } }

    public void Show()
    {
        t.Start(this);
    }

    private void ShowOFD(object o)
    {
        OpenFileDialog ofd = new OpenFileDialog();
        result = ofd.ShowDialog();
    }
}

С помощью этого кода вы можете добавить что-нибудь для запуска события в вашем потоке пользовательского интерфейса (будьте осторожны с вызовом!), Чтобы знать, когда они будут выполнены. Вы можете получить доступ к результату диалога по

DialogResult a = ofdThread.DialogResult

из вашего потока пользовательского интерфейса.

6 голосов
/ 26 января 2009

Нет, OpenFileDialog и SaveFileDialog оба являются производными от FileDialog , который по своей природе является модальным, поэтому (насколько я знаю) нет никакого способа создания немодальная версия любого из них.

1 голос
/ 22 марта 2011

Я знаю, что немного опоздал, но вы можете создать новую форму, без полей, прозрачную или за пределами границ экрана и показать диалоговое окно файла, изменяющее это окно.

0 голосов
/ 28 февраля 2017

Это старый пост, но я трачу 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

...