【问题标题】:WPF OpenFileDialog Suppresses ExceptionWPF OpenFileDialog 抑制异常
【发布时间】:2011-07-18 20:34:42
【问题描述】:

也许我错误地使用了OpenFileDialog,但我发现每当使用OpenFileDialog 并将结果传递到我的模型时,都会抑制未处理的异常。

通常我会在 AppDomain.CurrentDomain.UnhandledException 事件中挂钩以处理任何未处理的异常,但在使用 OpenFileDialog 后引发的任何异常都会被整个吞下。

以下是重现此行为的示例。如果您运行该示例,您将看到在后面的代码中引发的异常和 ShellModel.ThrowException 属性被 App.xaml.cs 中的 UnHandledException 处理程序正确捕获。但是,使用 OpenFileDialog 后在 ShellModel.OpenFile 属性中引发的异常被抑制。

为什么要禁止这些异常?

App.xaml.cs

using System;
using System.Text;
using System.Windows;

namespace ExceptionTest
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        protected override void OnStartup( StartupEventArgs e )
        {
            base.OnStartup( e );

            AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
        }

        private void OnUnhandledException( object sender, UnhandledExceptionEventArgs e )
        {
            var ex = e.ExceptionObject as Exception;

            if( ex == null )
            {
                MessageBox.Show( string.Format( "Null Exception: {0}", e ) );
                return;
            }

            var sb = new StringBuilder();
            sb.AppendLine( "An unhandled exception was encountered. Terminating now." );
            sb.AppendLine();
            sb.AppendLine( "Exception:" );
            sb.AppendLine( ex.Message );

            MessageBox.Show( sb.ToString(), "Whoops...", MessageBoxButton.OK, MessageBoxImage.Error );

            Environment.Exit( 1 );
        }
    }
}

Shell.xaml

<Window x:Class="ExceptionTest.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:Model="clr-namespace:ExceptionTest"
        Title="Exception Test" Height="350" Width="350" WindowStartupLocation="CenterScreen">

    <Window.DataContext>
        <Model:ShellModel x:Name="Model" />
    </Window.DataContext>

    <StackPanel Orientation="Vertical" VerticalAlignment="Stretch">

        <Button 
            Click="OnCodeBehind" Margin="20"
            Content="Exception from code behind" Height="25" Width="250" />

        <Button 
           Click="OnThrowExeption"  Margin="20"
            Content="Exception from Model" Height="25" Width="250" />

        <Button 
            Click="OnFindFile" Margin="20"
            Content="Exception from OpenFileDialog" Height="25" Width="250" />

        <Label Content="{Binding OpenFile, Mode=TwoWay}" x:Name="OpenFile"
                     Height="28" HorizontalAlignment="Left"  VerticalAlignment="Top" Width="Auto" />

    </StackPanel>
</Window>

Shell.xaml.cs / 模型

using System;
using System.ComponentModel;
using System.IO;
using System.Reflection;
using System.Windows;
using Microsoft.Win32;  

namespace ExceptionTest
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class Shell : Window
    {
        private OpenFileDialog OpenDialog { get; set; }

        public Shell()
        {
            InitializeComponent();

            OpenDialog = new OpenFileDialog();
            string path = new Uri( Assembly.GetExecutingAssembly().CodeBase ).LocalPath;
            OpenDialog.InitialDirectory = Path.GetDirectoryName( path );
            OpenDialog.Multiselect = false;
            OpenDialog.Title = "Find File";
            OpenDialog.RestoreDirectory = true;
        }

        private void OnCodeBehind( object sender, RoutedEventArgs e )
        {
            throw new Exception( "Exception from Code Behind." );
        }

        private void OnThrowExeption( object sender, RoutedEventArgs e )
        {
            Model.ThrowException = "Test";
            e.Handled = true;
        }

        private void OnFindFile( object sender, RoutedEventArgs e )
        {
            OpenDialog.ShowDialog( this );

            string fileName = OpenDialog.FileName;

            if( !string.IsNullOrEmpty( fileName ) )
            {
                OpenDialog.InitialDirectory = Path.GetDirectoryName( fileName );
                OpenFile.Content = fileName;
            }
        }
    }

    public class ShellModel : INotifyPropertyChanged
    {
        private string _throwException;
        public string ThrowException
        {
            get { return _throwException; }
            set
            {
                _throwException = value;
                NotifyPropertyChanged( "ThrowException" );
                throw new Exception( "Exception from Model." );
            }
        }

        private string _openFile;
        public string OpenFile
        {
            get { return _openFile; }
            set
            {
                _openFile = value;
                NotifyPropertyChanged( "OpenFile" );
                throw new Exception( "Exception from Model after using OpenFileDialog." );
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged( String info )
        {
            if( PropertyChanged != null )
            {
                PropertyChanged( this, new PropertyChangedEventArgs( info ) );
            }
        }
    }
}

分辨率

如答案中所述,这不是 OpenFileDialog 问题,而是数据绑定问题。

布拉德利的回答和汉斯可能的重复链接指向了一些重要信息。链接/文章并没有完全提供我想出的解决方案,回复:我发现还有另一个我可以挂钩的异常:AppDomain.CurrentDomain.FirstChanceException

这是我App.Xaml.cs的修改版:

protected override void OnStartup( StartupEventArgs e )
{
    base.OnStartup( e );

    AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;

    // The FirstChanceException will catch binding errors
    AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;
}


private void OnFirstChanceException( object sender, FirstChanceExceptionEventArgs e )
{
  // do stuff
}

现在已捕获绑定错误!

【问题讨论】:

标签: c# wpf exception-handling openfiledialog unhandled-exception


【解决方案1】:

抑制异常的不是 OpenFileDialog,而是 WPF 数据绑定。默认情况下,从 C# 代码中抛出的任何涉及属性绑定的异常都将被数据绑定引擎吞没。 (您可以在代码中通过将OnFindFile 的内容替换为OpenFile.Content = "test"; 来证明这一点)。

要诊断数据绑定错误,请将侦听器添加到 PresentationTraceSources.DataBindingSource 跟踪源。 Bea Costa 有 a good blog post 描述如何做到这一点。

【讨论】:

  • 啊!非常感谢。我不认为 Bea 的博客文章提供了运行时解决方案,但它确实为我指明了正确的方向。我会用分辨率更新我的问题。
猜你喜欢
  • 2012-04-22
  • 1970-01-01
  • 2011-12-12
  • 2011-04-19
  • 2012-03-04
  • 2013-05-14
  • 2019-12-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多