提问人:Ricky Chen 提问时间:1/18/2023 最后编辑:Ricky Chen 更新时间:1/19/2023 访问量:134
WPF 在删除 ListBox 中的项并引发 NullReferenceException 时崩溃
WPF Crash when delete items in ListBox and throw NullReferenceException
问:
都
我的应用程序有时会崩溃并引发异常,当我删除 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();
}
}
答:
什么 System.Windows.Controls.VirtualizingStackPanel.GetMaxChildArrangeLength (IList children, Boolean isHorizontal) 方法:
列表框有一个 VirtualizingStackPanel,用于虚拟化其项。要做到这一点,它需要决定什么适合它。
WPF 有一个度量安排机制,它用来决定所有内容需要什么空间。它查看面板中的每个事物,并询问它想要什么空间,然后查看它有什么限制,并决定它可以作为测量值。然后它安排一切。然后渲染。
GetMaxChildArrangeLength 显然决定了它能够在视口中容纳多少个项目。
你有这个错误,因为当涉及到它试图安排的其中一件事时,它会变成空。
您似乎无法重现此错误。
因此,任何修复都必须具有某种程度的推测性。一个猜测。
我的猜测是你的一个或两个转换器太复杂了。也许正在调用的索引转换器实际上是虚拟化的,并且没有容器。
它也可能是您的图像转换器MatToBmp导致的。
我看不到它的来源,但我猜这是一个昂贵的过程,因为你让它异步。
我的建议是让这两者都做更少的工作。让它们更简单或避免它们。
通过将 AlternationCount 设置为高 - 喜欢 10,0000 并绑定到 AlternationIndex,可以更轻松地获取项目索引。添加 1。
{Binding
RelativeSource={RelativeSource Mode=TemplatedParent},
Path=(ItemsControl.AlternationIndex)}
或者,从视图模型中公开索引 int 并重新计算。
同样,为该图像指定一个固定高度,以减少每个模板中的度量排列。
减少 MatToBmp 正在做的工作。提前构建位图源什么的。
评论