[英]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()
或者我是否尝试返回null
或string.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.