C# OpenFileDialog Non-Modal possible

2019-01-08 00:51发布

Is it possible to create/have a non-modal .net OpenFileDialog I have a UI element in the main dialog which always need to be available for the user to press.

4条回答
够拽才男人
2楼-- · 2019-01-08 01:28

No, OpenFileDialog and SaveFileDialog are both derived from FileDialog, which is inherently modal, so (as far as I know) there's no way of creating a non-modal version of either of them.

查看更多
forever°为你锁心
3楼-- · 2019-01-08 01:33

It is an old post but I spend 2 days reaching the result I want to present here ( with "context" and complete but simplified code ) @Joshua 's answer worked for me ( at last when I put true to .ConfigureAwait(true), see first code sample). Maybe I was able to write less lines based on the long article of MSDN Threading Model that I still need to read once again.

My context is WPF ( basic MVVM ) and I must choose a file in order to write some .CSV backup ( of a datagrid ). I need that the (member) function ChooseFileFromExtension() be asynchronous with a non-blocking 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
        }
    }
}

and the code for MyFileDialog class

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;
    }
}

The fetcher.BeginInvoke() launches (asynchronously) the SaveFileDialog ShowDialog() in another thread so that the main UI Thread / Window (...++) are neither blocked nor disabled as they would have been with a simple direct call to ShowDialog(). TaskCompletionSource<string> tcs is not an WPF UI Object so its access by another "single" thread is OK.

It is still a field that I need to study further. I feel there is no "ultimate" documentation/book on the subject ( maybe should have a second look to books like the one from Stephen Cleary again). This code should be improved at least with topic covered on c-sharp-asynchronous-call-without-endinvoke

It works with the FileDialog of namespace Microsoft.Win32

查看更多
可以哭但决不认输i
4楼-- · 2019-01-08 01:46

You can create a thread and have the thread host the OpenFileDialog. Example code is lacking any kind of synchronization but it works.

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();
    }
}

With this code you could add something to fire an event in your UI thread (be careful with invoking!) to know when they're done. You can access the result of the dialog by

DialogResult a = ofdThread.DialogResult

from your UI thread.

查看更多
劳资没心,怎么记你
5楼-- · 2019-01-08 01:50

I know I am a little late but you may create a new form, borderless, transparent or outside the display bounds and show the file dialog modding that window.

查看更多
登录 后发表回答