WPF baml错误:静态资源中的EventSetter设置了两次,第二次设置为null

WPF baml错误:静态资源中的EventSetter设置了两次,第二次设置为null,wpf,visual-studio-2013,staticresource,eventsetter,Wpf,Visual Studio 2013,Staticresource,Eventsetter,如果我试图在xaml中存储SetterBase对象的集合,包括和EventSetter,xaml加载程序将抛出一个错误 根本原因是xaml加载程序试图设置PresentationFramework.dll!System.Windows.EventSetters.Event两次:第一次为正确的值(ButtonBase.Click RoutedEvent),第二次为null,这会引发异常。不涉及我的附加属性回调 为什么它两次尝试将事件添加到EventSetter,第二次为什么为null?我检查了使用

如果我试图在xaml中存储SetterBase对象的集合,包括和EventSetter,xaml加载程序将抛出一个错误

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

为什么它两次尝试将事件添加到EventSetter,第二次为什么为null?我检查了使用的ctor是否为默认ctor,因此EventSeetter没有以任何异常方式与集合交互,所以不是这样。实际原因是wpf中的一个bug,它解决了解析事件的两部分结构(事件和事件处理程序)的难题

看法 错误 调试 我在System.Windows.EventSetter.Event处设置了一个函数断点,并使用一个操作记录传递给setter的值

然后我运行应用程序并检查输出窗口,可以看到setter被击中两次,第一次是正确的值,第二次是空值

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

baml 通过在XamlNodeList的索引成员中设置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: "
XamlNode[0]“无:LineInfo:System.Xaml.LineInfo”
XamlNode[1]“StartObject:SetterBaseCollection”
XamlNode[2]“StartMember:\u项”
XamlNode[3]“无:LineInfo:System.Xaml.LineInfo”
XamlNode[4]“StartObject:Setter”
XamlNode[5]“StartMember:属性”
XamlNode[6]“值:高度”
XamlNode[7]“结束成员:”
XamlNode[8]“StartMember:值”
XamlNode[9]“值:30”
XamlNode[10]“结束成员:”
XamlNode[11]“无:LineInfo:System.Xaml.LineInfo”
XamlNode[12]“内对象:”
XamlNode[13]“无:LineInfo:System.Xaml.LineInfo”
XamlNode[14]“无:LineInfo:System.Xaml.LineInfo”
XamlNode[15]“StartObject:EventSetter”
XamlNode[16]“StartMember:事件”
XamlNode[17]“值:System.Windows.Baml2006.TypeConverterMarkupExtension”
XamlNode[18]“结束成员:”
-->EventSetter值:{System.Windows.RouteEvent}
XamlNode[19]“无:LineInfo:System.Xaml.LineInfo”
XamlNode[20]“StartMember:事件”
XamlNode[21]{System.NullReferenceException:对象引用未设置为对象的实例。
位于…\AppData\Local\JetBrains\Shared\v06\DecompilerCache\…\XamlNode.cs中的System.Xaml.XamlNode.ToString()处:第159行
在x.m0处(XamlNode&4__this)}
XamlNode[22]“结束成员:”
-->EventSetter值:null
!!!然后抛出空引用错误
XamlNode[23]=“StartMember:处理程序”
XamlNode[24]=“值:样式单击”
XamlNode[25]=“端成员:”
XamlNode[26]=“无:LineInfo:System.Xaml.LineInfo”
XamlNode[27]=“内对象:”
XamlNode[28]=“端成员:”
XamlNode[29]=“内对象:”
XamlNode[30]=“无:”
41个节点中的其余节点均为“无”:
虫子? baml节点列表看起来很奇怪,首先有一个从idx[20]开始的额外事件成员,该成员实际上是一个System.NullReferenceException。
这将传递给XamlObjectWriter,然后再传递给EventSetter属性,这就是错误的原因。
然后,baml按预期进行,显示处理程序成员并正确终止成员和对象

结论 问题在于从xaml到baml的转换,所以我认为这是一个bug。尽管这是一个可以避免的边缘情况

变通 与其尝试在样式中设置事件,不如在父对象中使用附着的特性。例如,StackPanel中的ButtonBase.Click=“StyleClick”会将行为传递给clicky,这是我最初尝试做的。属性设置器的集合仍然可以在静态资源中设置,并由附加的基于属性的行为使用


对根本原因的进一步研究 问题在于事件属性有两个元素:事件和处理程序。当解析baml中的对象时,需要考虑其结构,以确保其处于正确状态,从而忠实地解释对象成员。为此,它有一个状态机,由while循环驱动,名为。此方法解码下一个xamlNodeType并调用适当的方法来解析它并将其作为对象写入。调用其中一个方法,并将特殊逻辑硬连接到其中,以处理baml中的事件复合体


问题在于,如果将事件记录在baml中作为事件,则此方法不知道事件的特殊要求,并且会将所有内容填充起来。事件处理程序以属性标记作为前缀(最有可能的是事件解析器将递归并使用与此子结构相同的语法),并且由于没有EndMember、StartMember状态更改,因此ReadObject将处理程序子属性解释为事件属性。正在创建的事件设置器对象抛出错误,因为它的事件属性已设置。

能否确保在这一行之后
var ui=d as UIElementui是否不为空并已加载?听起来您的
ui元素
在您尝试使用的时候没有加载it@lokusking,对不起,当我简化示例时,我应该从问题中删除该代码,它不涉及。让我重新表达我的评论。您所描述的问题似乎来自于当UIElements第一次从XAML加载时的情况,但行为不是这样。另外,我的第一条评论中的行仍然存在于您的edit@lokusking,很抱歉混淆了,有很多排列,我正试图找到最小的排列。希望现在更清楚。如果存在竞争,那么它完全在xaml加载程序中。事件的代码路径
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);
}
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
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: "