【问题标题】:WPF DataTemplate multibinding causes FrameworkElement.ApplyTemplate() to throw NullReferenceExceptionWPF DataTemplate 多重绑定导致 FrameworkElement.ApplyTemplate() 抛出 NullReferenceException
【发布时间】:2013-10-23 21:14:56
【问题描述】:

给出一些上下文:我有一个项目列表,我为每个项目绘制了一个图像。 它们都有黑色边框,但与给定的“画笔”属性绑定到同一对象的边框。那个有一个红色边框来显示哪个画笔被选中。

这里是代码

<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <StackPanel Orientation="Horizontal"/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Border BorderBrush="Black"
                BorderThickness="2 2 2 2">
            <Border.Style>
                <Style TargetType="{x:Type Border}">
                    <Style.Triggers>
                        <DataTrigger Value="True">
                            <DataTrigger.Binding>
                                <MultiBinding Converter="{StaticResource ResourceKey=AreEqualConverter}">
                                    <Binding/>
                                    <Binding ElementName="Me" Path="Brush"/>
                                </MultiBinding>
                            </DataTrigger.Binding>
                            <Setter Property="BorderBrush" Value="Red"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Border.Style>
            <Image Source="{Binding}" 
                   Height="{Binding ElementName=TilePreviewSize, Path=Value}"
                   Width="{Binding ElementName=TilePreviewSize, Path=Value}"
                   RenderOptions.BitmapScalingMode="NearestNeighbor"
                   MouseDown="OnBrushMouseDown"/>
        </Border>
    </DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

我收到以下错误“NullReferenceException:对象引用未设置为对象的实例。”当以下代码块未注释时。不知道是什么问题。

<Style TargetType="{x:Type Border}">
    <Style.Triggers>
        <DataTrigger Value="True">
            <DataTrigger.Binding>
                <MultiBinding Converter="{StaticResource ResourceKey=AreEqualConverter}">
                    <Binding/>
                    <Binding ElementName="Me" Path="Brush"/>
                </MultiBinding>
            </DataTrigger.Binding>
            <Setter Property="BorderBrush" Value="Red"/>
        </DataTrigger>
    </Style.Triggers>
</Style>

如果你想看转换器的代码,这里是(很简单)

public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    if (values.Length < 2)
        throw new NotSupportedException();

    var obj = values[0];

    for (int i = 1; i < values.Length; ++i)
        if (!values[i].Equals(obj))
            return false;

    return true;
}

这是堆栈跟踪或错误:

   at IntegratorUI.Contexts.RoomContext.System.Windows.Markup.IStyleConnector.Connect(Int32 connectionId, Object target) in [...] line 138
   at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlReader templateReader, XamlObjectWriter currentWriter)
   at System.Windows.FrameworkTemplate.LoadTemplateXaml(XamlObjectWriter objectWriter)
   at System.Windows.FrameworkTemplate.LoadOptimizedTemplateContent(DependencyObject container, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)
   at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren)
   at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)
   at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)
   at System.Windows.FrameworkElement.ApplyTemplate()
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.Controls.StackPanel.MeasureOverride(Size constraint)
   at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
   at System.Windows.UIElement.Measure(Size availableSize)
   at System.Windows.ContextLayoutManager.UpdateLayout()
   at System.Windows.ContextLayoutManager.UpdateLayoutCallback(Object arg)
   at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
   at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
   at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.DispatcherOperation.InvokeImpl()
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Threading.DispatcherOperation.Invoke()
   at System.Windows.Threading.Dispatcher.ProcessQueue()
   at System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.WrappedInvoke(Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.InvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run()
   at IntegratorUI.App.Main() in D:\trollmeme\integrator\IntegratorUI\obj\Debug\App.g.cs:line 0
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

感谢您帮我解决这个问题!

网卡

【问题讨论】:

    标签: c# wpf xaml binding multibinding


    【解决方案1】:

    数组中的一些值可以是null。使用静态Equals 方法。检查obj 是否不为空也是谨慎的做法。

    if (!Object.Equals(values[i], obj))
    

    更新

    查看您的堆栈跟踪后,您的问题似乎与this 问题有关。似乎当您使用 nested 模板/样式时。这会影响 .NET 4,并且似乎已在 .NET 4.5 中得到修复。建议的解决方法是将样式引用为资源。

    <UserControl.Resources>
       <Style x:Key="MyBorder" TargetType="{x:Type Border}" ...
    </UserControl.Resources>
    
    <DataTemplate>
        <Border BorderBrush="Black"
                BorderThickness="2 2 2 2"
                Style="{StaticResource MyBorder}" ...
    </DataTemplate>
    

    请注意,如果您的整个 ItemsControl 嵌套在另一个模板中,您可能应该将所有这些模板移动到资源中。

    【讨论】:

    • 是的,可以使用静态 Equals,但这并不能真正解释我得到的运行时 wpf 错误。至于 obj != null 检查,如果 Lenght
    • 是的,您正在检查长度,但可能(当然)数组中填充了空值?
    • 不,您将空值与数组成员混淆了。对象数组可以是任意长度,完全用空值填充。在多重绑定中,数组的长度是绑定子节点的数量,所有子节点都可以产生空值。 NullReferenceException 发生是因为您在空数组项上调用 instance Equals 方法。
    • 我再次遇到运行时 WPF 错误,将更新并尝试查找调用堆栈。
    【解决方案2】:

    您的问题是您在DataTemplate 内定义了MouseDown="OnBrushMouseDown"; 的处理程序。因此它无法正确检索 MouseButtonEventHandler。

    要解决此问题,请在样式的资源字典中添加新样式:

    <Style x:Key="MouseDownHandlerStyle" TargetType="{x:Type Image}">
        <EventSetter Event="MouseDown" Handler="OnBrushMouseDown"/>
    </Style>
    

    干杯!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-29
      • 2015-01-29
      • 2011-07-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多