WPF baml bug:静态资源中的 EventSetter 被设置两次,第二次为 null

2023-12-11

如果我尝试在 xaml 中存储 SetterBase 对象的集合(其中包括 EventSetter),则 xaml 加载器会引发错误。

根本原因是 xaml 加载器尝试两次设置PresentationFramework.dll!System.Windows.EventSetters.Event:第一次设置为正确值 (ButtonBase.Click RoutedEvent),但第二次设置为 null,这会引发异常。我的附加属性回调不涉及。

为什么它尝试将事件添加到 EventSetter 两次,为什么第二次它为空?我检查了正在使用的 ctor 是默认的,因此,EventSeetter 不会以任何不寻常的方式与集合交互,所以不是这样。真正的原因是 wpf 中的一个错误,它解决了解析事件的两部分结构(Event 和 EventHandler)的挑战。

View

<Window x:Class="Spec.Plain.MTCMinimal"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ContentToggleButton;assembly=ContentToggleButton"
        Title="MTCMinimal" Height="300" Width="300">

<Window.Resources>

    <SetterBaseCollection x:Key="ButtonStyleSetters">
        <Setter Property="FrameworkElement.Height" Value="30"></Setter>
        <EventSetter Event="ButtonBase.Click" Handler="StyleClick" />
    </SetterBaseCollection>

</Window.Resources>

<Button Name="Button1"
        local:Behaviours.StyleSetters="{StaticResource ButtonStyleSetters}" />

后面的代码只是 InitializeComponent 和事件处理程序的存根。该错误发生在InitializeComponent 期间。

行为

public static readonly DependencyProperty StyleSettersProperty =
    DependencyProperty.RegisterAttached(
        "StyleSetters", typeof(MyStyleSetters),
        typeof(Behaviours),
        new PropertyMetadata(default(MyStyleSetters),
            ButtonSettersChanged));

private static void ButtonSettersChanged (DependencyObject d,
    DependencyPropertyChangedEventArgs args)
{
    var fe = d as FrameworkElement;
    if (fe == null) return;
    var ui = d as UIElement;

    var newValue = args.NewValue as MyStyleSetters;
    if (newValue != null)
    {
        foreach (var member in newValue)
        {
            var setter = member as Setter;
            if(setter != null)
            {
                fe.SetValue(setter.Property, setter.Value);
                continue;
            }
            var eventSetter = member as EventSetter;
            if (eventSetter == null) continue;
            if (ui == null || eventSetter.Event == null) continue;
            ui.AddHandler(eventSetter.Event, eventSetter.Handler);
        }
    }
}

public static void SetStyleSetters(DependencyObject element,
    MyStyleSetters value)
{
    element.SetValue(StyleSettersProperty, value);
}

public static MyStyleSetters GetStyleSetters (
    DependencyObject element)
{
    return (MyStyleSetters)element
        .GetValue(StyleSettersProperty);
}

Error

System.Windows.Markup.XamlParseException occurred
  _HResult=-2146233087
  _message='Set property 'System.Windows.EventSetter.Event' threw an exception.' Line number '11' and line position '26'.
  HResult=-2146233087
  IsTransient=false
  Message='Set property 'System.Windows.EventSetter.Event' threw an exception.' Line number '11' and line position '26'.
  Source=PresentationFramework
  LineNumber=11
  LinePosition=26
  StackTrace:
       at System.Windows.Markup.XamlReader.RewrapException(Exception e, IXamlLineInfo lineInfo, Uri baseUri)
  InnerException: System.ArgumentNullException
       _HResult=-2147467261
       _message=Value cannot be null.
       HResult=-2147467261
       IsTransient=false
       Message=Value cannot be null.
Parameter name: value
       Source=PresentationFramework
       ParamName=value
       StackTrace:
            at System.Windows.EventSetter.set_Event(RoutedEvent value)
       InnerException

调试

我在 System.Windows.EventSetter.Event 设置了一个函数断点,并执行了一个操作来记录传递给 setter 的值...

enter image description here

然后我运行应用程序并检查输出窗口,可以看到设置器被击中两次,第一次使用正确的值,第二次使用值 null...

enter image description here

工作示例可以在解决方案中找到GITHub 仓库在名为 EventSetterNull-SO-41604891-2670182 的项目中

baml

通过在 XamlNodeList 的 Index 成员中设置 BP,我可以捕获与 SetterBaseCollection xaml 对象关联的 xaml 符号...

XamlNode [0] "None: LineInfo: System.Xaml.LineInfo"
XamlNode [1] "StartObject: SetterBaseCollection"
XamlNode [2] "StartMember: _Items"
XamlNode [3] "None: LineInfo: System.Xaml.LineInfo"
XamlNode [4] "StartObject: Setter"
XamlNode [5] "StartMember: Property"
XamlNode [6] "Value: Height"
XamlNode [7] "EndMember: "
XamlNode [8] "StartMember: Value"
XamlNode [9] "Value: 30"
XamlNode [10] "EndMember: "
XamlNode [11] "None: LineInfo: System.Xaml.LineInfo"
XamlNode [12] "EndObject: "
XamlNode [13] "None: LineInfo: System.Xaml.LineInfo"
XamlNode [14] "None: LineInfo: System.Xaml.LineInfo"
XamlNode [15] "StartObject: EventSetter"
XamlNode [16] "StartMember: Event"
XamlNode [17] "Value: System.Windows.Baml2006.TypeConverterMarkupExtension"
XamlNode [18] "EndMember: "
               -->EventSetter value: {System.Windows.RoutedEvent}
XamlNode [19] "None: LineInfo: System.Xaml.LineInfo"
XamlNode [20] "StartMember: Event"
XamlNode [21] {System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Xaml.XamlNode.ToString() in ...\AppData\Local\JetBrains\Shared\v06\DecompilerCache\...\XamlNode.cs:line 159
   at <>x.<>m0(XamlNode& <>4__this)}
XamlNode [22] "EndMember: "
               -->EventSetter value: null
               !!!Then the null reference error throws
XamlNode [23] = "StartMember: Handler"
XamlNode [24] = "Value: StyleClick"
XamlNode [25] = "EndMember: "
XamlNode [26] = "None: LineInfo: System.Xaml.LineInfo"
XamlNode [27] = "EndObject: "
XamlNode [28] = "EndMember: "
XamlNode [29] = "EndObject: "
XamlNode [30] = "None: "
                 The remaining of the 41 nodes are all "None: "

The Bug?

baml nodeList看起来很奇怪,首先有一个从idx [20]开始的额外Event成员,而这个成员实际上是一个System.NullReferenceException。
它被传递到 XamlObjectWriter,而 XamlObjectWriter 又被传递到 EventSetter 属性,这就是错误的原因。
然后 baml 按预期继续运行,显示处理程序成员并正确终止成员和对象。

结论

问题出在从 xaml 到 baml 的转换中,所以我认为这是一个错误。尽管是可以避免的边缘情况。

解决方法

不要尝试在样式中设置事件,而是使用父对象中的附加属性。例如,StackPanel 中的 ButtonBase.Click="StyleClick" 会将行为传递给所有可点击的内容,这正是我最初想要做的。属性设置器的集合仍然可以在静态资源中设置并由附加的基于属性的行为使用。


进一步研究根本原因

问题是事件属性有两个元素:事件和处理程序。当。。。的时候Baml2006读者解析 baml 中的对象,需要考虑其结构以确保其处于正确的状态以忠实地解释对象成员。为此,它有一个状态机,由 while 循环驱动读取对象,称为Process_OneBamlRecord。此方法解码下一个 xamlNodeType 并调用适当的方法来解析它并将其写入为对象。其中一种方法称为进程属性并且它具有硬连线的特殊逻辑来处理 baml 中的事件复合体。

问题是,如果事件在 baml 中记录为Process_PropertyWithConverter,这种方法不知道事件的特殊要求,并且把所有东西都塞满了。事件处理程序以属性标记为前缀(很可能事件解析器打算递归并为此子结构使用相同的语法),并且因为没有 EndMember、StartMember 状态更改,所以处理程序子属性由ReadObject 作为事件属性。正在创建的事件设置器对象会抛出错误,因为它的 Event 属性已经设置。


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

WPF baml bug:静态资源中的 EventSetter 被设置两次,第二次为 null 的相关文章

  • MVVM ViewModel 很多属性

    我是 MVVM 新手 正在开发一个应用程序 我有一个包含很多属性的表单视图 大约 50 个 我不能将它们分离到用户控件中 因为这会破坏 mvvm 原则 我无法将它们分成模型 因为它们包含逻辑 属性更改 错误更改这些都不是 poco 类 并且
  • 如何从用户控件引发自定义路由事件?

    在我的用户控件中 我有一个按钮 单击该按钮时会引发自定义路由事件 我试图引发它 但它没有在 MainWindow xaml 中被触发 UserControl 中按钮的 Xaml
  • 当 DataTable 为空时,DataGrid 显示空行

    我有一个DataGrid dg1 绑定到DataTable 数据集 表 代码运行良好并且DataGrid正在显示数据DataTable正确 但是 如果我Clear the DataTable the DataGrid也很清楚 但留下一个空行
  • 当事件button.click发生时,如何获取按钮名称/标签?

    我以编程方式制作按钮并将它们添加到堆栈面板中 以便每次用户导航到页面时按钮都会发生变化 我正在尝试做这样的事情 当我单击创建的按钮时 它将获取按钮的标签并转到正确的页面 但是 我无法使用 RoutedEventHandler 访问按钮元素
  • 已发布的 .Net Core 应用程序警告安装 .Net Core,但它已安装

    我制作了一个 WPF 和控制台应用程序 供某人在我无法访问的私人服务器上使用 我使用 Visual Studio 2019 的内置 发布向导 来创建依赖于框架的单文件应用程序 当该人打开 WPF 应用程序时 他们会看到标准警告 他们单击 是
  • EntityFramework 6.0.0.0 读取数据,但不插入

    我创建了一个基于服务的数据库 folderName gt Add New Item gt Data gt Service based Database文件到 WPF 应用程序中 然后我用过Database First方法并创建了Person
  • 为什么在 Windows 中缩放 WPF 应用程序时会看到像素?

    我使用 WPF 为随机应用程序开发了一个 GUI 我在应用程序窗口上放置了一堆开箱即用的 WPF 控件 我没有定制任何东西 没有使用位图等 在 Windows 7 中运行我的应用程序并使用放大镜应用程序进行缩放时 Win key Plus
  • C# - WPF - 组合框 - 将鼠标悬停在聚焦的组合框上时防止滚动(使用附加属性)

    背景 我需要防止ComboBox从将鼠标悬停在其上 聚焦时 时滚动和使用鼠标滚轮滚动 在这种情况下 我无法使用隐藏代码 因此我使用附加属性 我刚问这个问题 https stackoverflow com questions 76101509
  • GridSplitter 从右侧调整大小 - 奇怪的行为

    使用 Kaxaml 从左侧调整大小可以按预期工作
  • Brush 属性的 WPF ColorAnimation

    我想知道是否有人可以帮助我 我有一个标签 当在后面的代码中调用方法时 我需要能够在任意两种颜色之间交叉淡入淡出 迄今为止我最好的尝试 Private OldColor as Color Colors White Sub SetPulseCo
  • WPF 本地化扩展 MVVM 绑定

    我正在尝试绑定在 ViewModel 中声明的名为 SampleName 的属性 这里 SampleName 是关键 但是 当尝试下面的代码时 它显示为空
  • ResourceDictionary WPF 中样式的交互触发器

    我有一个ComboBox我需要在应用程序的多个地方使用它 所以我设置了它的大部分属性ComboBox in ResourceDictionary并在我需要的地方将其用作样式 风格为ComboBox is
  • WPF 缩放变换和 ScrollViewer - 缩放时无法滚动超出原始大小

    我在 ScrollViewer 中有一个 StackPanel 我有一个滑块 可以在堆栈面板上进行缩放变换 以允许放大和缩小功能 问题是 当我放大时 滚动查看器不会将内容视为 更大 因此 如果我滚动一点并尽可能向右滚动 它会在我到达内容末尾
  • 如何在Phone类库项目中添加ResourceDictionary并访问它

    我正在开发一个项目 其中我有一个引用图书馆项目的子项目 在我的库项目 电话类库 中 如何创建 ResourceDictionary xaml 其中我需要添加一些样式并在 xaml 文件和 cs 文件中使用它 我需要访问 xaml 文件中的
  • WPF 日历控件按住鼠标

    所以我放弃了标准的 WPFCalendarVS2010 中全新 WPF 应用程序中的 MainWindow xaml 控件 如果我单击日历中的某一天 然后尝试单击应用程序的 关闭 按钮 则我必须在关闭按钮上单击两次才能接受单击 它的表现就好
  • RichTextbox SelectionStart 返回错误的索引

    我需要向用户显示光标上文本的选择开始和长度 就像在 notepad exe 中一样 选择长度没有问题 因为 Richtextbox 支持带有开始和结束的选择属性 http msdn microsoft com en us library s
  • GridViewColumn 中的 WPF 文本格式设置

    我想将格式 对齐文本 货币格式 0000 00 应用于 GridViewColumn 中的列
  • 使用 WPF 动态加载内容

    好的 我有一个容器 我为其创建了两个数据模板 基本上 一个模板将显示 5 个文本框 其中包含绑定到它们的对象数据 另一个模板将显示一个用于添加该特定对象的按钮 我对 DataTemplateSelector 进行了子类化 它可以工作 但是当
  • WPF 从主线程以外的其他线程截屏

    我有一个线程用于侦听 WPF 应用程序的命令 如果 WPF 应用程序收到截取屏幕截图的命令 则任务将移交给 screenshotService 我在互联网上的某个地方找到了一些代码来截取屏幕截图 似乎可以工作 但我还没有想清楚 我无法从另一
  • Visual Studio Cordova 模板/AngularJSTodo 示例项目调试问题

    全新安装 Visual studio 2013 update 4 和 Cordova 工具集 尝试启动基本 cordova 模板或 AngularJsTodo 示例项目的调试最终会在 js 文件末尾中断 看链接 我可以单击 继续 并进入 C

随机推荐

  • openpyxl 按值查找单元格或行

    如果我有一个值而不是迭代整个文档来搜索它 是否有人知道我可以在哪里找到文档中的单元格或行 情况是 我需要比较非常大的电子表格 并且我通过使用每张表格中每条记录中存在的单个 UUID 来进行比较 所以 基本上 ws1 rows1 ws2 ro
  • 南迁移期间 Django GenericRelation 字段不可用

    在 Django 项目中 我定义的模型如下 from django db import models from django contrib contenttypes models import ContentType from djang
  • 使用两个等长数组执行数学运算

    我正在做的事情是如此简单 以至于我正在努力寻找答案 我正在尝试将两个等长数组相减 free array get wmiobject class win32 logicaldisk select ExpandProperty freespac
  • 使用 Hibernate 时如何将 Serialized 更改为 String

    我正在使用 Hibernate 从 MS SQL 创建实体类 但使用 NVARCHAR Hibernate 更改为可序列化类型 当我 CRUD 时 由于 NVARCHAR 和 Serialized 之间的冲突 它会出现一些错误 例外 当 H
  • 泛型方法中的隐式类型转换

    为什么我在以下代码中收到编译器错误 Cannot implicty convert type SpecialNode to T即使 T 必须从 NodeBase 派生 正如我在 where 子句中定义的那样 即使 SpecialNode 实
  • 汇总汇总数据

    我有一个如下表 SoftwareName Count Country Project 15 Canada Visio 12 Canada Project 10 USA Visio 5 USA 我如何查询它才能给我一个总结 例如 Softwa
  • DocuSign Connect X.509 证书身份验证/安全

    如何保护我的 DocuSign Connect https 侦听器 以便仅接受来自 DocuSign 的请求 我已阅读 Connect 服务指南 但不清楚以下设置是否可用于此目的 使用 X509 证书签署消息 此设置是否同时适用于 SOAP
  • 向量化矩阵的 min()

    我希望对以下循环进行矢量化 for i in 1 n for j in 1 m temp mat i j min temp mat i j 1 我以为我能做到temp mat min temp mat 1 但这并没有给我想要的结果 有没有办
  • 当应用程序以不同方式打开/关闭时显示推送通知

    在我的应用程序中 我有多个继承自一个 BaseActivity 的 Activity 我的应用程序收到推送通知GCMBaseIntentService我需要实现下一个逻辑 收到推送时 如果应用程序打开 则显示对话框 如果关闭 则显示通知 M
  • UWP NetworkConnectionChanged 事件

    我正在开发一个UWP应用程序 需要在失去网络连接或设备再次连接后执行一些操作 连接丢失或连接后是否会触发任何事件 我搜索了 www 但我发现的所有内容都是针对 WP8 的 我需要这个用于 Windows 10 上的 UWP 我尝试使用Net
  • 谷歌地图在div中没有​​完全渲染?

    在这里我有map canvas在一个div called map 问题是当我增加width of the map 一侧的谷歌地图未完全渲染 请帮忙 地图区域的宽度正在增加 但地图的右侧未完全渲染 当改变div的大小时 触发地图上的resiz
  • LINQ - 连接多个列表

    我查看了 101 个 Linq 示例here但我在该列表中看不到类似的内容 如果我在那里没有看到相关示例 请链接到它 如果我有这 3 门课 class Student int id string name class Course int
  • 为什么 POST 请求不总是经过预检?

    根据MDN 如果 Content Type 是以下任意一种 则不会预检 POST 请求application x www form urlencoded multipart form data or text plain 但不是multip
  • RDFa OfferCatalog 语法

    我一直在尝试找到使用 RDFa 将两个项目链接在一起的最佳方法 特别是将一个人链接到多个 SoftwareApplication 条目 我目前在作者页面上执行此操作的方式是 div class container text center s
  • Swift - 结构体或字典

    一般来说 在存储字典式结构化数据时 例如 let menuItems title View Profile icon iconSideProfile title Invite Friends icon iconSideHeart title
  • 如何在不使用对话框的情况下在 C# 项目中为 MySQL 数据库设置连接字符串?

    注意 显然 MySQL 连接器安装没有自动显示在添加数据源的对话框中的原因是 Visual 2008 速成版 不允许在 Visual Studio IDE 中进行 第三方集成 因此 这使得手动设置数据源变得更加重要 因为不存在来自 MySQ
  • 更新 Laravel 5.3 中的一对多关系

    我想更新一对多关系 例如我有一个名为Product class Product extends Model protected primaryKey product id public timestamps FALSE public fun
  • 被触摸的 UIView 的名称

    如何在touchesbegan事件中获取 touch view 的名称 所以如果它是 UIView aaaaaview 我会得到 aaaaaview 作为返回 谢谢你 不不不 UIView aaaaaView 只是指内存中的一个位置 所以如
  • 将 Alexa 与 Twitter 关联的帐户 - Amazon Echo

    截至目前 我似乎无法将我的 Alexa 技能与 Twitter 关联起来 目前 我有一个在 EBS 上运行的节点 express 服务器 我正在使用它护照推特处理身份验证的 oauth 部分 现在我的流程是这样的 在 Alexa 应用程序中
  • WPF baml bug:静态资源中的 EventSetter 被设置两次,第二次为 null

    如果我尝试在 xaml 中存储 SetterBase 对象的集合 其中包括 EventSetter 则 xaml 加载器会引发错误 根本原因是 xaml 加载器尝试两次设置PresentationFramework dll System W