2

我正在尝试创建一个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 消息:运行时遇到致命错误。错误地址位于线程 0x156c 上的 0xe7376797。错误代码为 0x80131623。此错误可能是 CLR 中的错​​误或用户代码的不安全或不可验证部分中的错误。此错误的常见来源包括 COM 互操作或 PInvoke 的用户封送错误,这可能会损坏堆栈。

4

2 回答 2

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;
    }
于 2013-04-17T09:33:03.427 回答
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);
于 2020-06-18T02:48:15.233 回答