10

I'm new to C#, but i've done a lots of java. Here's my problem : I'm trying to open a "SaveFileDialog" from a thread that is not the UI thread.

This is exactly what I try to do:

public partial class Form1: Form { public string AskSaveFile() { var sfd = new SaveFileDialog(); sfd.Filter = "Fichiers txt (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"; sfd.FilterIndex = 1; sfd.RestoreDirectory = true; DialogResult result = (DialogResult) Invoke(new Action(() => sfd.ShowDialog(this))); if(result == DialogResult.OK) { return sfd.FileName; } return null; } } 

This method will always be called from a thread different from the one who owns the Form. The problem is that when I execute this code, the "Form1" freeze and the "SaveFileDialog" doesn't show up.

Do you have some clue to help me to show the dialog from an independant thread?

2 Answers 2

15

Make it look like this:

 public string AskSaveFile() { if (this.InvokeRequired) { return (string)Invoke(new Func<string>(() => AskSaveFile())); } else { var sfd = new SaveFileDialog(); sfd.Filter = "Fichiers txt (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"; sfd.FilterIndex = 1; sfd.RestoreDirectory = true; return sfd.ShowDialog() == DialogResult.OK ? sfd.FileName : null; } } 

If you still get deadlock then be sure to use the debugger's Debug > Windows > Threads window and look at what the UI thread is doing. Control.Invoke() cannot complete unless the UI thread is idle and executing Application.Run(). If it isn't, like waiting for the worker thread to finish, then this code is always going to deadlock.

Also consider that this kind of code is risky from a UI usability perspective. The user might not expect this dialog to suddenly show up and could accidentally close it while mousing or keyboarding in the window(s) owned by the UI thread.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks this worked for me. I used it in FolderBrowserDialog
7

Try this:

public partial class Form1: Form { public string AskSaveFile() { if (this.InvokeRequired) { Invoke( new MethodInvoker( delegate() { AskSaveFile(); } ) ); } else { var sfd = new SaveFileDialog(); sfd.Filter = "Fichiers txt (*.txt)|*.txt|Tous les fichiers (*.*)|*.*"; sfd.FilterIndex = 1; sfd.RestoreDirectory = true; if(sfd.ShowDialog() == DialogResult.OK) return sfd.FileName; } return null; } } 

5 Comments

Not working : "AskSaveFile" needs to return a string. And if i wait for the result with "EndInvoke" I got the same problem ("Form1" freezing).
First part of new code makes Dialog executed in main thread... so this could work.... Oh, yes, main thread will execute this.. but do you mean your main thread is doing something different and could not be used? Believe me, I use this code in different threads in my apps and it works... so there must be something I don't understand right now...
@Hans: is your comment for me or for Mathieu?
You're right, the first part is working, it shows the dialog. But I've found a solution. I've set my thread who invoke the method as "STA", and it's now this one who execute the method "sfd.ShowDialog()".
For you. The C# compiler won't let you write code that doesn't guarantee that the return value is always set.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.