我正在尝试创建一个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()
无关紧要,或者我尝试返回null
或string.Empty
。
这真的是一个CLR错误(就像错误文本所暗示的那样)或者我在这里做些蠢事吗?
编辑:
MDA消息读取
检测到FatalExecutionEngineError消息:运行时具有 遇到致命错误。错误的地址是0xe7376797, 在线程0x156c上。错误代码是0x80131623。这个错误可能是一个 CLR中的错误或用户的不安全或不可验证部分 码。此错误的常见来源包括用户编组错误 COM-interop或PInvoke,可能会破坏堆栈。
答案 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);