PresentationFrame中出现NullReference异常



下面是一个最小的例子,我不可能再减少它了。

我在ViewModel中创建了一个实时过滤的CollectionView,如下所示:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Data;
using System.Windows;
namespace AntiBonto.ViewModel
{
[Serializable]
public class Person
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public string Name { get; set; }
public override string ToString()
{
return Name;
}
private int num;
public int Num
{
get { return num; }
set { num = value; RaisePropertyChanged(); }
}
}
class ObservableCollection2<T> : ObservableCollection<T>
{
public ObservableCollection2() : base() { }
public ObservableCollection2(T[] t) : base(t) { }
public void AddRange(IEnumerable<T> collection)
{
foreach (var i in collection)
{
Items.Add(i);
}
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
class MainWindow: ViewModelBase
{
public MainWindow() { }
private ObservableCollection2<Person> people = new ObservableCollection2<Person>();
public ObservableCollection2<Person> People
{
get
{
return people;
}
set
{
people = value;
RaisePropertyChanged();
}
}
public ICollectionView Team
{
get
{
CollectionViewSource cvs = new CollectionViewSource { Source = People, IsLiveFilteringRequested = true, LiveFilteringProperties = { "Num" } };
cvs.View.Filter = p => ((Person)p).Num != 11;
return cvs.View;
}
}
public ICollectionView Ujoncok
{
get
{
CollectionViewSource cvs = new CollectionViewSource { Source = People, IsLiveFilteringRequested = true, LiveFilteringProperties = { "Num" } };
cvs.View.Filter = p => ((Person)p).Num == 11;
return cvs.View;
}
}
}
}

GUI有一个按钮,用于修改People集合中的Person对象:

<Window x:Class="AntiBonto.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:AntiBonto.ViewModel"
mc:Ignorable="d"
Title="AntiBonto" Width="1024" Height="768">
<Window.DataContext>
<vm:MainWindow/>
</Window.DataContext>
<Window.Resources>
<FrameworkElement x:Key="DataContextProxy" DataContext="{Binding}"/> <!-- workaround, see http://stackoverflow.com/questions/7660967 -->
</Window.Resources>
<TabControl>
<TabItem Header="Tab2">
<StackPanel>
<Button Content="Does" Click="Button_Click"/>
<ContentControl Visibility="Collapsed" Content="{StaticResource DataContextProxy}"/>
<!-- workaround part 2 -->
<DataGrid ItemsSource="{Binding Ujoncok}" CanUserAddRows="False" CanUserDeleteRows="False" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Who" ItemsSource="{Binding DataContext.Team, Source={StaticResource DataContextProxy}, Mode=OneWay}"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</TabItem>
</TabControl>
</Window>

我从这样的XML文件加载数据:

using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Xml.Serialization;
namespace AntiBonto
{
[Serializable]
public class AppData
{
public Person[] Persons;
}
public partial class MainWindow : System.Windows.Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private string filepath = "state.xml";
private AppData AppData
{
get { return new AppData { Persons = viewModel.People.ToArray()}; }
set { viewModel.People.AddRange(value.Persons);}
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
var xs = new XmlSerializer(typeof(AppData));
if (File.Exists(filepath))
{
using (var file = new StreamReader(filepath))
{
AppData = (AppData)xs.Deserialize(file);
}
}
}     
private ViewModel.MainWindow viewModel { get { return (ViewModel.MainWindow)DataContext; } }
private void Button_Click(object sender, RoutedEventArgs e)
{
Person p = viewModel.People.First(q => q.Name == "Ferencz Katalin");
if (p.Num == 11)
p.Num = 0;
else
p.Num= 11;
}
}
}

XML文件是这样的:

<?xml version="1.0" encoding="utf-8"?>
<AppData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Persons>
<Person>
<Name>Person1</Name>
<Num>0</Num>
</Person>
<Person>
<Name>Person2</Name>
<Num>0</Num>
</Person>
</Persons>
</AppData>

当我单击该按钮一到两次时,我会得到一个NullReference异常。内部没有例外。异常不会出现在我的代码中,而是出现在框架代码中,因此它不会显示源,我无法找出哪个对象为null以及异常来自哪里。我没有设法设置"逐步进入.NET源代码",它仍然告诉我没有可用的源代码。

这是一个堆栈跟踪:

位于System.Windows.Data.ListCollectionView.RestoreLiveShaping()System.Windows.Threading.ExceptionWrapper.InternalRealCall(委托callback,Object args,Int32 numArgs)System.Windows.Threading.ExceptionWrapper.TryCatchWhen(对象源,委托回调,Object args,Int32 numArgs,Delegate catchHandler)位于System.Windows.Threading.DispatcherOperation.IInvokeImpl()System.Windows.Threading.DispatcherOperation.IInvokeInSecurityContext(对象州)System.Threading.ExecutionContext.RunInternal(ExecutionContextexecutionContext,ContextCallback回调,对象状态,布尔值preserveSyncCtx)System.Threading.ExecutionContext.Run(ExecutionContextexecutionContext,ContextCallback回调,对象状态,布尔值preserveSyncCtx)System.Threading.ExecutionContext.Run(ExecutionContextexecutionContext、ContextCallback回调、对象状态)MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContextexecutionContext、ContextCallback回调、对象状态)位于的System.Windows.Threading.DispatcherOperation.IInvoke()位于的System.Windows.Threading.Dispatcher.ProcessQueue()System.Windows.Threading.Dispatcher.WndProcHook(IntPtr hwnd,Int32msg,IntPtr wParam,IntPtr lParam,布尔值&已处理)MS.Win32.HwndWrapper.WndProc(IntPtr hwnd,Int32 msg,IntPtr wParam,IntPtr lParam,布尔型&已处理)位于的MS.Win32.HwndSubclass.DispatcherCallbackOperation(对象o)System.Windows.Threading.ExceptionWrapper.InternalRealCall(委托callback,Object args,Int32 numArgs)System.Windows.Threading.ExceptionWrapper.TryCatchWhen(对象源,委托回调,Object args,Int32 numArgs,Delegate catchHandler)在System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority优先级,TimeSpan超时,委托方法,对象参数,Int32numArgs)在MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd,Int32msg,IntPtr wParam,IntPtr lParam)MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG&MSG)位于System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame框架)System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame框架)位于System.Windows.Application.RunDispatcher(忽略对象)位于的System.Windows.Application.RunInternal(窗口窗口)System.Windows.Application.Run(窗口窗口)中的AntiBonto.App.Main()上的System.Windows.Application.Run()D: \Marci\Programozás\AntiBonto\AntiBonto\obj\Debug\App.g.cs:第0行System.AppDomain_nExecuteAssembly(RuntimeAssembly程序集,String[]args)(字符串assemblyFile,处的Evidence assemblySecurity,String[]args)位于的Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()位于的System.Threading.ThreadHelper.ThreadStart_Context(对象状态)System.Threading.ExecutionContext.RunInternal(ExecutionContextexecutionContext,ContextCallback回调,对象状态,布尔值preserveSyncCtx)System.Threading.ExecutionContext.Run(ExecutionContextexecutionContext,ContextCallback回调,对象状态,布尔值preserveSyncCtx)System.Threading.ExecutionContext.Run(ExecutionContextexecutionContext、ContextCallback回调、对象状态)System.Threading.ThreadHelper.ThreadStart()

我不知道为什么,但这修复了错误:

public ICollectionView Team
{
get
{
CollectionViewSource cvs = new CollectionViewSource { Source = People, IsLiveFilteringRequested = true, LiveFilteringProperties = { "Num" } };
cvs.View.Filter = p => ((Person)p).Num != 11;
cvs.View.CollectionChanged += EmptyEventHandler;
return cvs.View;
}
}
private void EmptyEventHandler(object sender, NotifyCollectionChangedEventArgs e) { }

我试图调试异常发生的位置,并且希望在集合更改时设置一个断点。订阅该事件使异常消失。

我花了很长时间调试System.Windows,但没有成功,欢迎您尝试。

就至少能起作用的创可贴解决方案而言,从我的问题中,我发现new CollectionViewSource会导致问题,而CollectionViewSource.GetDefaultView不会。

你提到这有两个问题:

1)我一直在修改基本集合,需要我的过滤器来刷新

您可以通过使用ObservableCollections并侦听版本,然后更新过滤后的实例来解决此问题。

因此,对于每一个需要CollectionViewSource的新时间,创建一个新的ObservableCollection,并跟踪它,向原始的Observable Collection添加一个侦听器,并推送CollectionViewSource版本的更新。

优雅?没有功能?对

2)我使用的是GetDefaultView无法使用的Live Shaping

我总是可以使用GetDefaultView,你能显示你在哪里创建视图吗?

我注意到的一个相似之处是,我使用了ObservableCollection的扩展。如果你只是使用一个标准的ObservableCollection,你会有问题吗?

最新更新