[WPF 容易忽视的细节] —— Exception in WPF's Converter

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 原文:[WPF 容易忽视的细节] —— Exception in WPF's Converter前言: 在WPF中,Converter是我们经常要用到的一个工具,因为XAML上绑定的数据不一定是我们需要的数据。
原文: [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 = 0; i < 5; 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 = 0;

        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

相关实践学习
通过日志服务实现云资源OSS的安全审计
本实验介绍如何通过日志服务实现云资源OSS的安全审计。
目录
相关文章
|
开发框架 前端开发 JavaScript
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(8) -- 使用Converter类实现内容的转义处理
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(8) -- 使用Converter类实现内容的转义处理
|
C#
【WPF】wpf用MultiBinding解决Converter需要动态传参的问题,以Button为例
原文:【WPF】wpf用MultiBinding解决Converter需要动态传参的问题,以Button为例       用Binding并通过Converter转换的时候,可能偶尔会遇到传参的问题,一般通过设置xaml中的BindingParameter属性来给Converter传递参数。
2071 0
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
619 0
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
288 1
|
C# Windows
WPF技术之RichTextBox控件
WPF RichTextBox是Windows Presentation Foundation (WPF)中提供的一个强大的文本编辑控件,它可以显示富文本格式的文本,支持多种文本处理操作。
862 0
|
前端开发 C# 容器
浅谈WPF之控件拖拽与拖动
使用过office的visio软件画图的小伙伴都知道,画图软件分为两部分,左侧图形库,存放各种图标,右侧是一个画布,将左侧图形库的图标控件拖拽到右侧画布,就会生成一个新的控件,并且可以自由拖动。那如何在WPF程序中,实现类似的功能呢?今天就以一个简单的小例子,简述如何在WPF中实现控件的拖拽和拖动,仅供学习分享使用,如有不足之处,还请指正。
365 2
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
|
C# 开发者 Windows
一款基于Fluent设计风格、现代化的WPF UI控件库
一款基于Fluent设计风格、现代化的WPF UI控件库
298 1
|
C# Windows
WPF中如何使用HandyCotrol控件库
WPF中如何使用HandyCotrol控件库
540 1
|
开发框架 前端开发 JavaScript
WPF应用开发之控件动态内容展示
WPF应用开发之控件动态内容展示