UI异常处理
在UI代码中,如果出现异常或者错误,则往往需要代码捕获这些错误信息并整理成用户可接受的材料展现在UI上。
SilverLight中提供了方便的机制用于捕获和向用户展现错误信息。
我们假设提供一个页面,当程序有Exception时,可以将Exception信息完整的展现在页面中。
首先,在项目中加入一个页面专门用于显示错误信息。
在页面中添加一个TextBlock.
<Border BorderBrush="White"> <TextBlock x:Name="ErrorText" Style="{StaticResource PhoneTextSmallStyle}" TextWrapping="Wrap" /> </Border> |
在页面中添加如下代码:
public static Exception Exception;
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) { ErrorText.Text = Exception.ToString(); } |
这段代码首先定义了一个静态变量Exception,用于传入异常信息。
然后覆盖了页面的OnNavigatedTo方法,代码的功能很明显:当页面载入的时候,页面上的TextBlock控件将显示Exception的内容。
现在的问题是,如何控制当应用程序出现异常时自动跳转到这个页面来,并且能正确的显示Exception信息。
现在打开前面提到过的App.xaml.cs文件。可以从中找到两个方法:
// Code to execute if a navigation fails private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) { if (System.Diagnostics.Debugger.IsAttached) { // A navigation has failed; break into the debugger System.Diagnostics.Debugger.Break(); } }
// Code to execute on Unhandled Exceptions private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) { if (System.Diagnostics.Debugger.IsAttached) { // An unhandled exception has occurred; break into the debugger System.Diagnostics.Debugger.Break(); } } |
通过注释可以很清楚的看到,这两个方法就可以用来帮助处理错误和异常。RootFrame_NavigationFailed用于处理导航失败。第二个方法Application_UnhandledException用来处理应用程序所有未处理的异常(没有在某个环节Catch住的异常)。
如果是在调试模式下,System.Diagnostics.Debugger.Break()将会使得断点停留在此处。这是一个很实用的功能,程序员有机会在这里查看runtime信息。
我们可以在某处故意抛出一个异常,例如在某个按钮中加入如下的代码:
private void button1_Click(object sender, RoutedEventArgs e) { NavigationService.Navigate(new Uri("NoExist.html", UriKind.Relative)); } |
然后在RootFrame_NavigationFailed中加入如下代码:
// Code to execute if a navigation fails private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) { if (System.Diagnostics.Debugger.IsAttached) { // A navigation has failed; break into the debugger System.Diagnostics.Debugger.Break(); } e.Handled = true;
ErrorPage.Exception = e.Exception; (RootVisual as Microsoft.Phone.Controls.PhoneApplicationFrame).Source = new Uri("/ErrorPage.xaml", UriKind.Relative); } |
运行测试,我们会发现,当点击产生错误的按钮后,如果在调试模式下,VisualStudio会首先会运行到System.Diagnostics.Debugger.Break();停止,继续运行后系统将转向我们设定的ErrorPage并显示错误信息:
代码中的:e.Handled = true可以避免继续处理该异常。如果没有这一句,系统会将异常最终传递到Application_UnhandledException函数进行处理。
现在我们将刚才的代码加至Application_UnhandledException中试试看:
// Code to execute on Unhandled Exceptions private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e) { if (System.Diagnostics.Debugger.IsAttached) { // An unhandled exception has occurred; break into the debugger System.Diagnostics.Debugger.Break(); }
e.Handled = true;
ErrorPage.Exception = e.ExceptionObject; (RootVisual as Microsoft.Phone.Controls.PhoneApplicationFrame).Source = new Uri("/ErrorPage.xaml", UriKind.Relative); } |
在调试模式下运行后,因为我们触发的是一个Navigation Failed的错误,所以程序首先会停在RootFrame_NavigationFailed的Debugger.Break()处,继续运行后,程序会停在Application_UnhandledException的Debugger.Break()处。再继续运行将得到和刚才一样的错误页面显示。
同样,如果没有e.Handled = true,则异常将抛出应用程序,其效果是导致应用程序直接关闭。
如果是一个面向消费者的应用软件,可以充分利用SilverLight提供的这一异常处理机制,为用户提供经过提炼的、适于用户的、有好的错误信息。