WPF OpenFileDialog подавляет исключение - PullRequest
1 голос
/ 19 марта 2011

Возможно, я неправильно использую OpenFileDialog, но я обнаружил, что необработанные исключения подавляются всякий раз, когда используется OpenFileDialog, и результат передается в мою модель.

Обычно я подключаю событие AppDomain.CurrentDomain.UnhandledException для обработки любых необработанных исключений, но любые исключения, возникающие после использования OpenFileDialog, проглатываются целиком.

Ниже приведен пример для воспроизведения этого поведения. Если вы запустите пример, вы увидите, что исключения, создаваемые в коде и свойстве ShellModel.ThrowException, корректно перехватываются обработчиком UnHandledException в App.xaml.cs. Однако исключение, которое выдается в свойстве 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 / Модель

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, а проблема привязки данных.

Ответ Брэдли и возможная двойная ссылка Ганса указали на некоторую полезную информацию Ссылки / статьи не совсем обеспечивают разрешение, которое я придумал, re: я обнаружил, что есть еще одно исключение, в которое я могу зацепиться: 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
}

Ошибки привязки теперь обнаруживаются!

1 Ответ

1 голос
/ 19 марта 2011

Подавляет исключение не OpenFileDialog, а привязка данных WPF.По умолчанию любое исключение, выбрасываемое из кода C #, который участвует в привязке свойства, будет проглочено механизмом привязки данных.(Вы можете продемонстрировать это в своем коде, заменив содержимое OnFindFile просто OpenFile.Content = "test";).

Чтобы диагностировать ошибки привязки данных, добавьте прослушиватель к трассировке PresentationTraceSources.DataBindingSourceисточник.У Bea Costa есть хороший пост в блоге , описывающий, как это сделать.

...