WPF - 随机挂起文件浏览器附加行为

时间:2009-12-18 17:18:10

标签: wpf attached-properties attachedbehaviors

我有一个如此定义的附加行为,..

    public static class FileBrowserBehaviour
{


    public static bool GetBrowsesOnClick(DependencyObject obj)
    {
        return (bool)obj.GetValue(BrowsesOnClickProperty);
    }

    public static void SetBrowsesOnClick(DependencyObject obj, bool value)
    {
        obj.SetValue(BrowsesOnClickProperty, value);
    }

    // Using a DependencyProperty as the backing store for BrowsesOnClick.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty BrowsesOnClickProperty =
        DependencyProperty.RegisterAttached("BrowsesOnClick", typeof(bool), typeof(FileBrowserBehaviour), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(BrowsesOnClickChanged)));


    public static void BrowsesOnClickChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        FrameworkElement fe = obj as FrameworkElement;

        if ((bool)args.NewValue)
        {
            fe.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(OpenFileBrowser);
        }
        else
        {
            fe.PreviewMouseLeftButtonDown -= new MouseButtonEventHandler(OpenFileBrowser);
        }
    }

    static void OpenFileBrowser(object sender, MouseButtonEventArgs e)
    {
        var tb = sender as TextBox;
        if (tb.Text.Length < 1 || tb.Text=="Click to browse..")
        {
            OpenFileDialog ofd = new OpenFileDialog();
                ofd.Filter = "Executables | *.exe";
                if (ofd.ShowDialog() == true)
                {
                    Debug.WriteLine("Setting textbox text-" + ofd.FileName);
                    tb.Text = ofd.FileName;
                    Debug.WriteLine("Set textbox text");
                }
        }
    }
}

这是一个很好的简单附加行为,当您单击文本框并在完成后将文件名放在框中时会弹出OpenFileDialog。

它的工作时间可能有40%,但剩下的时间整个应用程序都会挂起。此时的调用堆栈看起来像这样 -

[Managed to Native Transition]  
  

WindowsBase.dll!MS.Win32.UnsafeNativeMethods.GetMessageW(ref System.Windows.Interop.MSG msg,System.Runtime.InteropServices.HandleRef hWnd,int uMsgFilterMin,int uMsgFilterMax)+ 0x15 bytes
      WindowsBase.dll!System.Windows.Threading.Dispatcher.GetMessage(ref System.Windows.Interop.MSG msg,System.IntPtr hwnd,int minMessage,int maxMessage)+ 0x48 bytes       WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame frame = {System.Windows.Threading.DispatcherFrame})+ 0x8b bytes       WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame frame)+ 0x49 bytes
      WindowsBase.dll!System.Windows.Threading.Dispatcher.Run()+ 0x4c bytes
      PresentationFramework.dll!System.Windows.Application.RunDispatcher(对象忽略)+ 0x1e字节
      PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window window)+ 0x6f bytes       PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window window)+ 0x26 bytes       PresentationFramework.dll!System.Windows.Application.Run()+ 0x19字节       Debugatron.exe!Debugatron.App.Main()+ 0x5e字节C#       [原产于管理过渡]
      [管理到原生过渡]
      mscorlib.dll!System.AppDomain.nExecuteAssembly(System.Reflection.Assembly assembly,string [] args)+ 0x19 bytes       mscorlib.dll!System.Runtime.Hosting.ManifestRunner.Run(bool checkAptModel)+ 0x6e bytes       mscorlib.dll!System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly()+ 0x84 bytes       mscorlib.dll!System.Runtime.Hosting.ApplicationActivator.CreateInstance(System.ActivationContext activationContext,string [] activationCustomData)+ 0x65 bytes       mscorlib.dll!System.Runtime.Hosting.ApplicationActivator.CreateInstance(System.ActivationContext activationContext)+ 0xa bytes       mscorlib.dll!System.Activator.CreateInstance(System.ActivationContext activationContext)+ 0x3e bytes
      Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()+ 0x23 bytes
      mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(对象状态)+ 0x66字节
      mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext,System.Threading.ContextCallback callback,object state)+ 0x6f bytes
      mscorlib.dll!System.Threading.ThreadHelper.ThreadStart()+ 0x44 bytes

现在,我在做一些异步事情之前已经看到过这种事情了,但那时候并没有这样做。活着的唯一线程是UI线程!此外,我总是在挂起时获取最后一个调试语句。

有人能指出我正确的方向吗?这个让我疯狂!

2 个答案:

答案 0 :(得分:1)

这里有一些几乎随机的事实和问题,可能对你有所帮助。

首先,我无法重现您的问题。无论我多么努力。它总是奏效。

堆栈跟踪对我来说也很好看:它继续处理消息循环。究竟让你困惑的是什么?管理原生过渡?

WPF应用程序中不能有一个线程。您在VS Debugger的Threads窗口中看到了什么?

当我点击break时,我在主线程堆栈跟踪中看到对ofd.ShowDialog()的调用,并且一个名为.NET SystemEvents的工作线程停留在WindowThreadProc()中,等待同步对象。你看到了什么?

看起来你以某种方式陷入僵局。

尝试将OpenFileBrowser()内容包装到try... catch{}中。有什么错误吗?

答案 1 :(得分:1)

我有一个非常简单的WPF应用程序,它在WPF应用程序中使用WPF WebBrowser控件。我有完全一样的问题。当我水平调整窗口大小时,WPF WebBrowser控件(使用JavaScript启动Google Earth)会冻结大约75%的时间。我得到与上面列出的完全相同的堆栈转储。当我在另一台PC(所有正在运行的XP SP3)上复制/运行可执行文件时,它运行正常并且永不挂起。我还有一个更复杂的应用程序是多线程的,它也挂在这台PC上的类似堆栈转储(也在线程库中的消息上等待)但不是另一台PC。无论是针对.Net 3.5还是4.0,WPF WebBrowser控件应用程序都存在同样的问题。我使用NETfx_Setupverifier来验证.net安装是否正确,但我仍然怀疑.net或某些COM实用程序存在问题导致.NET-COM互操作不稳定。我也猜测我的应用程序正在等待一些因为互操作问题而永远无法到达的非托管事件/消息。我还使用WinForms / WinForm WebBrowser Control编写了相同的简单应用程序,该应用程序永远不会挂在同一台PC上。

有没有人对如何追查原因有任何建议?我正在考虑完全卸载/重新安装.NET框架,即使它们已经过验证是正确的。我甚至不知道在哪里寻找COM方面的异常情况。