[WPF 容易忽视的细节] —— Exception in WPF's Converter
前言:
在WPF中,Converter是我们经常要用到的一个工具,因为XAML上绑定的数据不一定是我们需要的数据。
问题:
在Converter中抛出一个异常导致程序崩溃,而且是在对未捕获异常进行集中处理的情况。
补充:错误场景。
<Window x:Class="TestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestProject"
Title="MainWindow"
Width="525"
Height="350"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Window.Resources>
<local:ErrorConverter x:Key="ErrorConverter" />
</Window.Resources>
<Grid>
<TextBlock Text="{Binding Content, Converter={StaticResource ErrorConverter}}" />
</Grid>
</Window>
namespace TestProject
{
using System;
using System.Globalization;
using System.Windows.Data; /// <summary>
/// 转换过程中跑出异常的Converter。
/// </summary>
public class ErrorConverter : IValueConverter
{
/// <summary>
/// 只抛出错误,不做任何错误。
/// </summary>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("Just for test! - In ErrorConverter - Convert");
} /// <summary>
/// 只抛出错误,不做任何错误。
/// </summary>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new Exception("Just for test! - In ErrorConverter - ConvertBack");
}
}
}
上面的场景中,当TextBlock绑定到Content时,便会触发ErrorConverter的Convert方法,
但是Convert方法因为抛出了异常,导致整个程序挂掉。
虽然,在App.xaml.cs中集中对未捕获异常进行处理,但是却无法捕获这个异常。
public App()
{
this.DispatcherUnhandledException +=new DispatcherUnhandledExceptionEventHandler(Application_DispatcherUnhandledException);
AppDomain.CurrentDomain.UnhandledException +=new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);
}
探索过程:
1、UnhandledException
因为程序中,难免会出现没有处理的异常,这些异常如果没有被处理就会先被抛给我们的主程序,
如果还未被处理就会被抛给.Net Framework,最终导致程序挂掉。
所以,我时常集中处理未被处理的这部分异常,以防止程序挂掉。
相关内容可以参考:CSharp UnhandledException。
当捕获到未被处理的异常时,我就会弹出一个消息框,然后打印到日志中。
理论上来说,这是可以捕获所有程序中抛出的异常的,但是当Converter中抛出异常时,却导致程序崩溃。
通过Debug,导致崩溃异常为StackOverflowException。
2、StackOverflowException
一方面这个异常的名字,是我已经去的一个网站;另外一方面这个异常是无法被捕捉的。
这是MSDN上的解释:StackOverflowException 。
而且,我的经验是一般出现这个异常就是说明程序中出现了死循环。
但是,当我检查程序时发现,我并没有写此类代码。
而且错误出现在MessageBox.Show("");这行。(就是我在主程序中处理未捕获的异常时,抛出消息框)。
// 当捕获未处理异常时
Exception ex = e.Exception;
const string errorMsg = "UI Thread Exception : \n\n";
MessageBox.Show("An unhandled UI Thread exception occurred");
Logger.Error(errorMsg + ex.Message + Environment.NewLine + ex.StackTrace);
e.Handled = true;
将此行注释掉,发现一切正常,程序不再挂掉。说明是MessageBox引起StackOverflowException。
3、 MessageBox
当MessageBox.Show("");时,会阻塞当前线程,所以理论上来说每次只能显示一个MessageBox。
// 点击按钮执行以下代码
// 只有点击MessageBox上的确认按钮才会显示下一个,不会一次全部显示。
for (int i = ; i < ; i++)
{
MessageBox.Show("Just For test");
}
说明应该是MessageBox.Show被多次调用,造成StackOverflowException。
4、 Logger
再去检查日志,发现没有日志信息打印出来,说明应该是一直停留在MessageBox.Show这里,
所以日志还没来得及打印程序便挂掉了。
5、Trace Converter
有一个猜想,就是Converter被调用了多次:当xaml解析器发现Converter抛出异常时,
便再次调用Converter,导致又一次抛出异常,主程序捕获后,又执行MessageBox.Show,
所以程序挂掉了。
验证猜想:
public class TestConverter : IValueConverter
{
// 临时变量,用于记录被调用的次数
private int temp = ; public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// 打印出次数
using (var writer = File.AppendText("D:\\Log.txt"))
{
writer.WriteLine(DateTime.Now + " - " + temp++);
} throw new Exception("Just for test!");
} public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
再次运行错误的程序,不例外程序崩溃,但是我也得到了想要的数据。
9/12/2013 3:01:42 PM - 0
9/12/2013 3:01:42 PM - 1
9/12/2013 3:01:42 PM - 2
9/12/2013 3:01:42 PM - 3
9/12/2013 3:01:42 PM - 4
9/12/2013 3:01:42 PM - 5
9/12/2013 3:01:42 PM - 6
9/12/2013 3:01:42 PM - 7
9/12/2013 3:01:42 PM - 8
9/12/2013 3:01:42 PM - 9
9/12/2013 3:01:43 PM - 10
9/12/2013 3:01:43 PM - 11
9/12/2013 3:01:43 PM - 12
9/12/2013 3:01:43 PM - 13
9/12/2013 3:01:43 PM - 14
跟我猜想的一样,但是Converter确被调用了15次,这也是导致程序崩溃的原因。
结论:
1、 当MessageBox.Show被同时多次调用时,会出现StackOverflowException的异常。
这个我不知道如何验证,但是貌似是这样的。
2、当xaml发现Converter抛出异常时,会继续执行Convert方法,最多15次。
完全不知道这个有什么意义,已经抛出异常了,再次调用就不会有异常?
3、尽量在Converter中将异常处理好,否则容易引起不必要的麻烦。
如果条件错误、或者转换失败,则返回null。而不是抛出异常。
写的时间比研究的时间长多了,希望对大家有帮助,希望大神能够回答我的疑问。
引用请注明出处:Exception in WPF's Converter
[WPF 容易忽视的细节] —— Exception in WPF's Converter的更多相关文章
- [WPF 容易忽视的细节] —— x:Name与Name属性
一.前言 WPF使用XAML来对界面进行编写,界面与后台逻辑分离.我们也可以写Style.Trigger来实现一些界面效果, 这些都是通过Name来定位控件的,例如Setter.TargetName. ...
- WPF Set connectionId threw an exception异常 以及重复dll的问题
1.DataOutputWPF 在显示norlib.Basic.UserConfigControl时 抛出异常 xmlparsingException : WPF Set connectionId t ...
- “WPF老矣,尚能饭否”—且说说WPF今生未来(上):担心
近日微软公布了最新的WPF路线图,一片热议:对于老牌控件提供商葡萄城来说,这是WPF系列控件一个重要的机遇,因此,Spread Studio for WPF产品做了一次重要更新,并随着Spread S ...
- WPF老矣,尚能饭否——且说说WPF今生未来(中):策略
本文接上文<WPF老矣,尚能饭否——且说说WPF今生未来(上):担心>继续. “上篇”中部分精彩的点评: 虽然WPF不再更新了,但是基于WPF的技术还是在发展着,就比如现在的WinRT,只 ...
- WPF老矣,尚能饭否——且说说WPF今生未来(下):安心
在前面的上.中篇中,我们已经可以看到园子里朋友的点评“后山见! WPF就比winform好! 激情对决”.看到大家热情洋溢的点评,做技术的我也很受感动.老实说,如何在本文收笔--WPF系列文章,我很紧 ...
- [WPF系列]基础学习(一) WPF是什么?
引言 学习之前,我们首先大概了解下WPF诞生的背景以及它所能解决的问题或者新颖之处.WPF作为微软新一代的用户界面技术, WPF简介 WPF的全称是WindowsPresentationFound ...
- WPF快速入门系列(5)——深入解析WPF命令
一.引言 WPF命令相对来说是一个崭新的概念,因为命令对于之前的WinForm根本没有实现这个概念,但是这并不影响我们学习WPF命令,因为设计模式中有命令模式,关于命令模式可以参考我设计模式的博文:h ...
- WPF快速入门系列(4)——深入解析WPF绑定
一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...
- wpfのuri(让你完全明白wpf的图片加载方式以及URI写法)
绝对 pack WPF URI pack://application:,,,/是协议:“,,,”是“///”的变体 1.资源文件 — 本地程序集 Uri uri = new Uri("pac ...
随机推荐
- PHP:WampServer下如何安装多个版本的PHP、mysql、apache
作为Web开发人员,在机器上安装不同版本的php,apache和mysql有时是很有必要的. 今天,我在调试一套PHP程序的时候,该程序中使用的某些函数在低版本中无法使用,所以只能在搞个高版本的php ...
- Mac 下使用 brew 安装软件
官网:http://brew.sh/安装 ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/m ...
- wordpress中常用的一些php代码
<?php the_author(); ?> 显示文章的作者 <?php the_author_description(); ?> 显示文章作者的描述(作者个人资料中的描述) ...
- 关于VS2017的安装和WDK的选择问题
首先就是关于VS2017的安装,我们可以通过微软的官网去寻找我们想要安装的VS版本 我们可以随便选择一个我们需要的版本进行下载,任意版本的VS都可以. 然后下载安装的时候,要进行一下这个安装选项的选择 ...
- PHP self this parent
{一}PHP中this,self,parent的区别之一this篇 面向对象编程(OOP,Object OrientedProgramming)现已经成为编程人员的一项基本技能.利用OOP的思想进行P ...
- [转]C# Bootstrap table之 分页
本文转自:https://www.cnblogs.com/zhangjd/p/7895453.html 效果如图: 一.声明talbe <div class="container&qu ...
- ASP的不足与ASP.NET和ASP的区别
ASP.Net和ASP的最大区别在于编程思维的转换,而不仅仅在于功能的增强.ASP使用VBS/JS这样的脚本语言混合html来编程,而那些脚本语言属于弱类型.面向结构的编程语言,而非面向对象,这就明显 ...
- C#网络爬虫--多线程处理强化版
上次做了一个帮公司妹子做了爬虫,不是很精致,这次公司项目里要用到,于是有做了一番修改,功能添加了网址图片采集,下载,线程处理界面网址图片下载等. 说说思路:首相获取初始网址的所有内容 在初始网址采集图 ...
- C# Windows程序窗口置前台的几种方法
这个是从别的地方看来的,放我这里 第一种:SetForegroundWindow,这个方法时灵时不灵.有人说,在自己的程序里把自己的窗口之前一般就不灵,而置前其它程序的窗口就灵.我觉得这是有原因的:当 ...
- Spring加载properties文件的两种方式
在项目中如果有些参数经常需要修改,或者后期可能需要修改,那我们最好把这些参数放到properties文件中,源代码中读取properties里面的配置,这样后期只需要改动properties文件即可, ...