Note that there are some explanatory texts on larger screens.

plurals
  1. POSaveFileDialog: InvalidOperationException due to "owner" parameter in a multi-threaded application
    text
    copied!<p>Sorry for the long post, but I tried to explain the problem very detailed so that no confusion should arise. The last sentence contains the actual question.</p> <p>I'm programming a multi-thread application with C#/.NET.</p> <p>The application consists of a main window, which visualizes data, coming from a pressure sensor. The sensor data is acquired in an own thread.</p> <p>The data is also logged in an instance of class <code>ListView</code>:</p> <p><img src="https://i.stack.imgur.com/iO05j.png" alt="enter image description here"></p> <p>There is the possibility to save the logged data to file on disk via a "Save" button (should open an instance of .NET class <code>SaveFileDialog</code>).</p> <p>This <code>SaveFileDialog</code> is also running in an own thread. Now there's a problem when calling the method <code>SaveFileDialog.ShowDialog()</code>:</p> <blockquote> <p>System.InvalidOperationException was unhandled Message="Cross-thread operation not valid: Control 'tlpMain' accessed from a thread other than the thread it was created on." Source="System.Windows.Forms"</p> </blockquote> <p>The problem arises because the owner (the main window) of the <strong>SaveFileDialog</strong> is running in another thread.</p> <p>Here's the code, which creates the thread for the SaveFileDialog():</p> <pre><code>private void bSave_Click(object sender, EventArgs e) { Thread saveFileDialog = new Thread(OpenSaveFileDialog); saveFileDialog.SetApartmentState(ApartmentState.STA); saveFileDialog.Start(); } </code></pre> <p>Code for method OpenSaveFileDialog():</p> <pre><code>private void OpenSaveFileDialog() { SaveFileDialog saveFileDialog = new SaveFileDialog(); saveFileDialog.Filter = "Text Files (*.txt)|*.txt|CSV (*.csv)|*.csv|All Files (*.*)|*.*"; saveFileDialog.FilterIndex = 0; /* Call "ShowDialog" with an owner ("this.Parent") to achieve, so that * the parent window is blocked and "unclickable". * * Danger of an "InvalidOperationException" because "this.Parent" control * is running (was created) in another thread. * But "this.Parent" should not be modified by this method call. */ DialogResult pressedButton = saveFileDialog.ShowDialog(this.Parent); ... </code></pre> <p>The <strong>InvalidOperationException</strong> is only thrown/displayed when running the application with Visual Studio's debugger. It is no problem - so far - when running the application "normally".</p> <p>But I would like to avoid this problem.</p> <p>I tried to build a wrapper method (SaveFileDialog):</p> <pre><code>private void OpenSaveFileDialog() { SaveFileDialog saveFileDialog = new SaveFileDialog(); ... SaveFileDialog(saveFileDialog, this.Parent); } </code></pre> <p>Wrapper method :</p> <pre><code>private void SaveFileDialog(SaveFileDialog saveFileDialog, Control owner) { if (owner.InvokeRequired) BeginInvoke(new dSaveFileDialog(SaveFileDialog), new object[] { saveFileDialog, owner }); else { DialogResult pressedButton = saveFileDialog.ShowDialog(owner); ... </code></pre> <p>This leads to a <code>TargetInvocationException</code> although the <code>Main()</code> method is labeled with <code>[STAThreadAttribute]</code>:</p> <blockquote> <p>InnerException: System.Threading.ThreadStateException Message="Current thread must be set to single thread apartment (STA) mode before OLE calls can be made. Ensure that your Main function has STAThreadAttribute marked on it. This exception is only raised if a debugger is attached to the process." Source="System.Windows.Forms"</p> </blockquote> <p>Does anybody have a clue how to open the <code>SaveFileDialog</code> in a way, so that the main window will be blocked ("unclickable") without having the (thread) trouble?</p> <p>Thank you.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload