也许我错误地使用OpenFileDialog
,但我发现只要使用OpenFileDialog
并且结果传递到我的模型中,就会抑制未处理的异常。
通常我会挂钩AppDomain.CurrentDomain.UnhandledException
事件来处理任何未处理的异常,但是使用OpenFileDialog
后引发的任何异常都会被吞没。
以下是重现此行为的示例。如果运行该示例,您将看到后面代码中抛出的异常和ShellModel.ThrowException
属性被App.xaml.cs中的UnHandledException
处理程序正确捕获。但是,使用ShellModel.OpenFile
后在OpenFileDialog
属性中抛出的异常将被禁止。
为什么要抑制这些例外?
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 / Model
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
}
现在抓住了绑定错误!
答案 0 :(得分:1)
OpenFileDialog不是抑制异常,而是WPF数据绑定。默认情况下,数据绑定引擎会吞下从属性绑定中涉及的C#代码抛出的任何异常。 (您可以在代码中通过仅使用OnFindFile
替换OpenFile.Content = "test";
的内容来证明这一点。)
要诊断数据绑定错误,请向PresentationTraceSources.DataBindingSource
跟踪源添加侦听器。 Bea Costa a good blog post描述了如何做到这一点。