简体   繁体   English

在 TextBlock 的 CoerceValueCallback 中添加内联时出现 FatalExecutionEngineError

[英]FatalExecutionEngineError when adding inlines in the CoerceValueCallback of a TextBlock

I am trying to create a TextBlock control that formats the text it is bound to in some way.我正在尝试创建一个TextBlock控件,该控件以某种方式对其绑定的文本进行格式化。 To achieve that, I tried to use the CoerceValueCallback of a class deriving from TextBlock to add the neccesary inlines, and then ignore the text.为了实现这一点,我尝试使用派生自 TextBlock 的类的 CoerceValueCallback 添加必要的内联,然后忽略文本。 Something like:就像是:

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;
    }
}

Now, when I use this control as soon as I change the Text property (either directly or by databinding) I get the FatalExecutionEngineError.现在,当我在更改 Text 属性(直接或通过数据绑定)后立即使用此控件时,我会收到 FatalExecutionEngineError。 It does not matter if I use tb.Inlines.Clear() before or not, or wether I try to return null or string.Empty .我之前是否使用tb.Inlines.Clear()或者我是否尝试返回nullstring.Empty

Is this really a CLR bug (like the error text implies) or am I doing something silly here?这真的是一个 CLR 错误(就像错误文本暗示的那样)还是我在这里做了一些愚蠢的事情?

Edit:编辑:

The MDA message reads MDA 消息读取

FatalExecutionEngineError was detected Message: The runtime has encountered a fatal error.检测到 FatalExecutionEngineError 消息:运行时遇到致命错误。 The address of the error was at 0xe7376797, on thread 0x156c.错误的地址是 0xe7376797,在线程 0x156c 上。 The error code is 0x80131623.错误代码是 0x80131623。 This error may be a bug in the CLR or in the unsafe or non-verifiable portions of user code.此错误可能是 CLR 或用户代码的不安全或不可验证部分中的错误。 Common sources of this bug include user marshaling errors for COM-interop or PInvoke, which may corrupt the stack.此错误的常见来源包括 COM 互操作或 PInvoke 的用户封送错误,这可能会损坏堆栈。

MainWindow主窗口

XAML 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>

Code-behind代码隐藏

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

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {

        myBug.Text = "new blubb";
    }

your code你的代码

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;
    }
}

Edit also if you do如果你这样做,也要编辑

    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;
    }

You can work around this situation with the following:您可以通过以下方式解决这种情况:

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;
    }
}

This will trigger automatically in most situations.这在大多数情况下会自动触发。 If you need to manually coerce the value at any time (such as in response to another property updating), just use:如果您需要随时手动强制该值(例如响应另一个属性更新),只需使用:

InvalidateProperty(TextProperty);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM