C# OpenFileDialog.ShowDialog 打不开,程序无响应(错误的解决)

1:C# OpenFileDialog.ShowDialog 打不开,程序无响应

环境:win7 .Net framework2.0
现象; c#写的一个程序,在xp下点击文件打开按钮没有任何问题,但在我的win7下,点击则不弹出打开文件对话框,程序忙且无响应
网上搜索其他人也出现过这样的问题,且有些计算机行有些不行。
给出解决办法为设置openFileDialog打开的缺省目录。
可是设置了后仍然不行,在win7下,点击打开无法弹出打开文件对话框且程序忙,无响应
继续搜索,发现一个帖子也是说这个问题,大致是主线程必须是单线程单元,否则可能会导致此问题,应在主线程上加 [STAThread] 属性
http://social.msdn.microsoft.com/Forums/zh-CN/vcgeneral/thread/105702a4-475d-4209-9730-c02cef7895e2
更改main函数的声明如下,问题解决。
[STAThread]
public static void Main(string[] args)

网上找到的关于[STAThread]的一些说明:
[STAThread]
STAThread:Single     Thread     Apartment Thread.(单一线程单元线程)
[]是用来表示Attributes;

[STAThread]
是一种线程模型,用在程序的入口方法上(在C#和VB.NET里是Main()方法),来指定当前线程的ApartmentState 是STA。用在其他方法上不产生影响。在aspx页面上可以使用AspCompat = "true" 来达到同样的效果。这个属性只在  Com  Interop  有用,如果全部是  managed  code  则无用。简单的说法:[STAThread]指示应用程序的默认线程模型是单线程单元 (STA)。启动线程模型可设置为单线程单元或多线程单元。如果未对其进行设置,则该线程不被初始化。也就是说如果你用的.NET Framework,并且没有使用COM Interop,一般不需要这个Attribute。其它的还有MTA(多线程套间)、Free  Thread(自由线程)。

[STAThread] attribute指示应用程序的 COM 线程模型是单线程单元。
而于此对应的多线程单元则是 [MTAThread] (多线程单元线程)

COM 线程模型只适用于使用 COM interop 的应用程序。如果将此属性应用到不使用 COM interop 的应用程序,将没有任何效果。

COM 线程模型可设置为单线程单元或多线程单元。如果应用程序线程实际调用了 COM 组件,则仅为 COM interop 初始化该线程。如果没有使用 COM interop,则不初始化该线程。

我又在网络上找了两篇文章或许更能说明这个问题。我没有翻译,文章的大意是,由于很多COM在.NET环境下如果使用多线程的话,会导致引用的COM不能正常运行,而如果不声明程序为STAThread的话,.NET就会自动使用多线程来提高效率,这样就会导致不可预知的后果。

Q. When I create a c# project from scratch in VS.NET, the generated code always have a [STAThread] attribute above the main routine. What does the STAThread attribute really do? Can I change it to MTAThread instead? I have searched website and books, no one seems to explain this well.

Asked by anon. Answered by the Wonk on February 17, 2003


A.

The STAThreadAttribute marks a thread to use the Single-Threaded COM Apartment if COM is needed. By default, .NET won't initialize COM at all. It's only when COM is needed, like when a COM object or COM Control is created or when drag 'n' drop is needed, that COM is initialized. When that happens, .NET calls the underlying CoInitializeEx function, which takes a flag indicating whether to join the thread to a multi-threaded or single-threaded apartment.

A multi-threaded apartment (MTA) in COM is more efficient, since any of a number of RPC threads from a pool can be used to handle a request. However, an object on the MTA thread needs to protect itself from multiple threads accessing it at the same time, so that efficiency comes at a cost.

The single-thread apartment (STA) in COM is inherently single-threaded and therefore no additional thread synchronization is needed. The STA is implemented using the thread's Windows message queue, which is how requests to objects on an STA are serialized. Because of how the STA thread is implemented, calls to objects on that thread are serialized with Windows message handling on that thread, making sure that everything, both the COM objects and the underlying windowing objects, e.g. HWNDs, are all synchronized. This is necessary for UI-oriented COM objects, like controls and drag 'n' drop, which must also be synchronized together with the UI.

When COM is needed .NET will call CoInitializeEx, picking the MTA by default because it's more efficient. However, to get the synchronization needed for controls, windows and drag 'n' drop, you need to mark a thread's entry point with the STAThreadAttribute to let .NET know to initialize the UI thread on the STA. All of the VS.NET project templates put that attribute in to make sure you don't forget:

[STAThread]
static void Main() {...}

Be very careful to leave that STAThreadAttribute just where it is, or things can go all wacky and you won't know why.

Original Source Link: http://www.sellsbrothers.com/askthewonk/Secure/WhatdoestheSTAThreadattri.htm

2:ShowDialog() 错误的解决

首先,一个类里,有个linkLabel1

private OpenFileDialog openFileDialog1;
private DialogResult result;

private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {

            openFileDialog1 = new OpenFileDialog();
            string patch = Application.StartupPath + "\\LOG\\";
            openFileDialog1.InitialDirectory = patch;
            openFileDialog1.Filter = "xls files (*.xls)|*.xls";

            result = openFileDialog1.ShowDialog();

            if (result == DialogResult.OK)
            {
                if (openFileDialog1.FileName != "")
                {
                    Process.Start(openFileDialog1.FileName);
                }
               
            }

           
        }

就会报 
在可以调用 OLE 之前,必须将当前线程设置为单线程单元(STA)模式。请确保您的 Main 函数带有 STAThreadAttribute 标记。 只有将调试器附加到该进程才会引发此异常。

在测试小程序里没有问题,当移到大程序里就这样的问题了。可能是线程多的原因。解决办法就是添加线程,代码如下

private Thread invokeThread;

private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            openFileDialog1 = new OpenFileDialog();
            openFileDialog1.InitialDirectory = patch;
            openFileDialog1.Filter = "xls files (*.xls)|*.xls";

            invokeThread = new Thread(new ThreadStart(InvokeMethod));
            invokeThread.SetApartmentState(ApartmentState.STA);
            invokeThread.Start();
            invokeThread.Join();

            if (result == DialogResult.OK)
            {
                if (openFileDialog1.FileName != "")
                {
                    Process.Start(openFileDialog1.FileName);
                }

            }
        }

private void InvokeMethod()
        {
            result = openFileDialog1.ShowDialog();
        }

问题得到解决

阅读更多
个人分类: WinForm学习
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭