在TextBlock的CoerceValueCallback中添加内联时发生FatalExecutionEngineError

时间:2013-04-17 08:58:06

标签: c# wpf

我正在尝试创建一个TextBlock控件,以某种方式格式化它所绑定的文本。为了实现这一点,我尝试使用从TextBlock派生的类的CoerceValueCallback来添加必要的内联,然后忽略文本。类似的东西:

public class BuggyTextBlock : TextBlock
{
    static BuggyTextBlock()
    {
        TextProperty.OverrideMetadata(typeof(BuggyTextBlock),
                      new FrameworkPropertyMetadata((PropertyChangedCallback)null,
                                                    CoerceText));
    }

    private static object CoerceText(DependencyObject sender, object value)
    {
        BuggyTextBlock tb= (BuggyTextBlock)sender;                       
        tb.Inlines.Add(new Run("Hello World")); // FatalExecutionEngineError here
        return string.Empty;
    }
}

现在,当我更改Text属性时(直接或通过数据绑定)我使用此控件时,我得到FatalExecutionEngineError。我之前是否使用tb.Inlines.Clear()无关紧要,或者我尝试返回nullstring.Empty

这真的是一个CLR错误(就像错误文本所暗示的那样)或者我在这里做些蠢事吗?

编辑:

MDA消息读取

  

检测到FatalExecutionEngineError消息:运行时具有   遇到致命错误。错误的地址是0xe7376797,   在线程0x156c上。错误代码是0x80131623。这个错误可能是一个   CLR中的错误或用户的不安全或不可验证部分   码。此错误的常见来源包括用户编组错误   COM-interop或PInvoke,可能会破坏堆栈。

2 个答案:

答案 0 :(得分:1)

主窗口

<强> XAML

xmlns:obj='clr-namespace:Jens' 
Height="350" Width="525" Loaded="Window_Loaded">

<obj:BuggyTextBlock Background="Gray" Width="100" Height="50" x:Name="myBug">

</obj:BuggyTextBlock>

<强>代码隐藏

    public MainWindow()
    {
        InitializeComponent();
        myBug.Text = "blubb";
    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        myBug.Text = "new blubb";
    }

您的代码

public class BuggyTextBlock : TextBlock
{
    static BuggyTextBlock()
    {
        TextProperty.OverrideMetadata(typeof(BuggyTextBlock),
                      new FrameworkPropertyMetadata((PropertyChangedCallback)null,
                                                    CoerceText));
    }

    private static object CoerceText(DependencyObject sender, object value)
    {
        // 1. value == blubb
        // 2. value == new blubb
        // and here it comes i don't know why but it get called 3 Times
        // 3. value == Hello WorldHello World <-- FatalExecutionEngineError here

        BuggyTextBlock tb = (BuggyTextBlock)sender; 
        tb.Inlines.Add(new Run("Hello World")); // FatalExecutionEngineError here
        return string.Empty;
    }
}

修改 如果你这样做

    private static object CoerceText(DependencyObject sender, object value)
    {
        BuggyTextBlock tb = (BuggyTextBlock)sender; 

        tb.Text = value //<- watch here you will get a StackOverflowException

        return string.Empty;
    }

答案 1 :(得分:1)

您可以通过以下方法解决这种情况:

class HighlightTextBlock : TextBlock
{
    static HighlightTextBlock()
    {
        TextProperty.OverrideMetadata(
            typeof(HighlightTextBlock),
            new FrameworkPropertyMetadata("", null, (d, e) => ((HighlightTextBlock)d).OnCoerceTextPropertyValue(e)));
    }

    private bool _isUpdating;

    private object OnCoerceTextPropertyValue(object baseValue)
    {
        if (_isUpdating)
        {
            return string.Empty;
        }

        // TODO if it is possible to modify baseValue directly, return that modified value here

        var condition = SomeLogicToDetermineWhetherWeShouldUpdate();

        _isUpdating = true;

        Inlines.Clear();

        // TODO add inlines here

        _isUpdating = false;

        return baseValue;
    }
}

在大多数情况下,这将自动触发。如果您需要随时手动强制值(例如响应另一个属性更新),请使用:

InvalidateProperty(TextProperty);