删除列表框中的项并引发NullReferenceException时WPF崩溃

tsm1rwdh  于 2023-01-21  发布在  其他
关注(0)|答案(1)|浏览(153)

全部
当我删除ListBox中的多个项目时,应用程序有时会崩溃并引发异常。
我通过ContextMenu的MenuItem中的delete命令删除项目。
我无法重现这个异常,它太奇怪了.
日志为:

‧ System.NullReferenceException: Object reference not set to an instance of an object.    
  at System.Windows.Controls.VirtualizingStackPanel.GetMaxChildArrangeLength(IList children, Boolean isHorizontal) 
  at System.Windows.Controls.VirtualizingStackPanel.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at MS.Internal.Helper.ArrangeElementWithSingleChild(UIElement element, Size arrangeSize)    
  at System.Windows.Controls.ItemsPresenter.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.ScrollContentPresenter.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Control.ArrangeOverride(Size arrangeBounds)    
  at System.Windows.Controls.ScrollViewer.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Border.ArrangeOverride(Size finalSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Control.ArrangeOverride(Size arrangeBounds)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at MS.Internal.Helper.ArrangeElementWithSingleChild(UIElement element, Size arrangeSize)    
  at System.Windows.Controls.ContentPresenter.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Border.ArrangeOverride(Size finalSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Control.ArrangeOverride(Size arrangeBounds)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.Controls.Grid.ArrangeOverride(Size arrangeSize)    
  at System.Windows.FrameworkElement.ArrangeCore(Rect finalRect)    
  at System.Windows.UIElement.Arrange(Rect finalRect)    
  at System.Windows.ContextLayoutManager.UpdateLayout()    
  at System.Windows.Interop.HwndSource.Process_WM_SIZE(UIElement rootUIElement, IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam)    
  at System.Windows.Interop.HwndSource.LayoutFilterMessage(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 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)

Xaml为:

<ListBox ItemsSource="{Binding ImgList}" SelectedItem="{Binding SelectedImg}" Style="{StaticResource ListBoxScroll}" SelectionMode="Extended" Background="#FF353535" HorizontalContentAlignment="Stretch" SelectionChanged="ListBox_SelectionChanged" BorderBrush="{x:Null}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0">
    <ListBox.ContextMenu>
        <ContextMenu>                            
           <MenuItem Header="Delete File" Command="{Binding DeleteImageFileCommand}"/>
        </ContextMenu>
    </ListBox.ContextMenu>
    <ListBox.Resources>
        <DataTemplate x:Key="ItemTemplate">
             <Border Height="117" Width="208" BorderBrush="#FF979797" BorderThickness="1" Margin="21,0,0,18">
                 <Grid>
                    <Label x:Name="Lab" Width="40" Height="20" Grid.Column="0" Content="{Binding Converter={StaticResource ItemToIndex}, Mode=OneWay, Path=., RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}" FontSize="14"  HorizontalContentAlignment="Center" VerticalContentAlignment="Center" HorizontalAlignment="Left" VerticalAlignment="Top" Padding="0" Panel.ZIndex="1" Background="White" BorderBrush="#FF353535" BorderThickness="1" Foreground="#FF011627" Margin="-1,-1,0,0"/>
                    <Image Grid.Column="1" Width="208" Source="{Binding SmallImg, Converter={StaticResource MatToBmp}, IsAsync=True}" Stretch="Uniform"/>
                </Grid>
            </Border>
        </DataTemplate>
    </ListBox.Resources>
</ListBox>

有人知道这个异常是如何被抛出的吗?我希望有人能帮助我,谢谢!

**更新:**我添加了下面的转换器代码,绑定为:<local:FilterIndexConverter x:Key="ItemToIndex"/>

public class FilterIndexConverter : IValueConverter
{
    public object Convert(object value, Type TargetType, object parameter, CultureInfo culture)
    {
        ListBoxItem item = (ListBoxItem)value;
        ListBox listBox = ItemsControl.ItemsControlFromItemContainer(item) as ListBox;
        int index = (listBox.ItemsSource as RangeObservableCollection<ImageInformation>).IndexOf((value as ListBoxItem).Content as ImageInformation);
        return index + 1;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
sgtfey8w

sgtfey8w1#

什么系统.窗口.控件.虚拟化StackPanel.GetMaxChildArrangeLength(IList子级,布尔值为水平)表示:
列表框有一个VirtualizingStackPanel,用于虚拟化列表框中的项目。为此,列表框需要决定哪些项目适合它。
WPF有一个度量安排机制,它用来决定每件事物需要什么样的空间。它查看面板中的每件事物,并询问它想要什么样的空间,然后查看它有什么约束,并决定它可以有什么作为度量。然后它安排每件事物,然后渲染。
https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/layout?view=netframeworkdesktop-4.8#LayoutSystem_Overview
GetMaxChildArrangeLength很明显决定了视口中可以容纳多少项。
出现这个错误是因为当它试图排列其中一个对象时,它会为空。
您似乎无法重现此错误。
因此,任何解决方案都必须带有一定的投机性,一种猜测。
我猜你的一个或者两个转换器都太复杂了,也许索引转换器被调用的对象实际上是虚拟化的,没有容器。
它也可能是/或者是你的图像转换器MatToBmp造成的。
我看不出它的来源,但我猜这是一个昂贵的过程,因为你把它异步。
我的建议是让这两个做更少的工作。使他们更简单或消除他们。
你可以通过设置AlternationCount高到10,0000并绑定到AlternationIndex来更容易地获得条目索引。

{Binding
     RelativeSource={RelativeSource Mode=TemplatedParent}, 
     Path=(ItemsControl.AlternationIndex)}

或者从视图模型中公开一个indexint并重新计算。
类似地,给予图像一个固定高度,以削减在每个模板中排列度量。
减少MatToBmp正在做的工作。提前构建bitmapsource之类的。

相关问题