2016-05-23 59 views
0

下面是一个最小的例子,我不可能再减少它。PresentationFramework中的空引用异常

我创建的视图模型的实时过滤的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有一个按钮,人民集合中修改一个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异常。没有内在的例外。这个异常在我的代码中没有出现,但是在框架代码中,所以它不显示源代码,我找不到哪个对象为空以及异常来自哪里。我没有设置“加入.NET资源”,但它仍然告诉我没有可用的源代码。

这里有一个堆栈跟踪:

在System.Windows.Data.ListCollectionView.RestoreLiveShaping()在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(代表 回调,对象指定参数时,的Int32 numArgs)在 System.Windows.Threading.ExceptionWrapper.TryCatchWhen(对象源, 代表回调,对象指定参数时,的Int32 numArgs,代表catchHandler) 在System.Windows.Threading.DispatcherOperation.InvokeImpl()在 System.Windows.Threading.DispatcherOperation。 InvokeInSecurityContext(对象 状态)在 System.Threading.ExecutionContext.RunInternal(的ExecutionContext 的ExecutionContext,ContextCallback回调,对象的状态,布尔 preserveSyncCtx)在 System.Threading.ExecutionContext.Run(的ExecutionContext 的ExecutionContext,ContextCallback回调,对象的状态,布尔 preserveSyncCtx )在 System.Threading.ExecutionContext.Run(的ExecutionContext 的ExecutionContext,ContextCallback回调,对象状态)在 MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext 的ExecutionContext,ContextCallback回调,对象状态)在 System.Windows.Threading.DispatcherOperation 。调用() System.Windows.Threading.Dispatcher.ProcessQueue()在 System.Windows.Threading.Dispatcher.WndProcHook(IntPtr的HWND,的Int32 味精,IntPtr的wParam中,IntPtr的lParam的,布尔&处理)在 MS.Win32.HwndWrapper.WndProc (IntPtr的HWND,MSG的Int32,IntPtr的wParam中,01​​IntPtr的lParam的,布尔&处理)在 MS.Win32.HwndSubclass.DispatcherCallbackOperation(对象O)在 System.Windows.Threading.ExceptionWrapper.InternalRealCall(代表 回调,对象指定参数时, Int32 numArgs)at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback,Object args,Int32 numArgs,Delegate catchHandler) at System.Windows.Threading.Dispatcher。LegacyInvokeImpl在MS.Win32.HwndSubclass.SubclassWndProc(IntPtr的HWND,的Int32 味精,IntPtr的wParam中,IntPtr的LPARAM)在 MS.Win32.UnsafeNativeMethods.DispatchMessage(的DispatcherPriority 优先权,时间跨度超时,委托方法, numArgs对象指定参数时,Int32)已(MSG & MSG)在 System.Windows.Threading.Dispatcher.PushFrameImpl在 System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame帧) (DispatcherFrame 帧)在System.Windows.Application.RunDispatcher(对象忽略)在 System.Windows.Application.RunInternal(Window window)at System.Windows.Application.Run(Window window)at System.Windows.Application.Run()at AntiBonto.App.Main() D:\ Marci \Programozás\ AntiBonto \ AntiBonto \ obj \ Debug \ App.g.cs:line 0 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly,String [] args)at System.AppDomain.ExecuteAssembly(字符串assemblyFile, 证据assemblySecurity,字串[] args)处 System.Threading.ThreadHelper.ThreadStart_Context(对象状态) Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()在 的System.Threading。 ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean preserveSyncCtx)at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallba CK回调,对象状态,布尔 preserveSyncCtx)在 System.Threading.ExecutionContext.Run(ExecutionContext中 的ExecutionContext,ContextCallback回调,对象状态)在 System.Threading.ThreadHelper.ThreadStart()

+1

@RenéVogt不,不是。 – marczellm

+0

cvs.View = new .... –

+1

我不会称之为重复的,只是因为它与另一个问题共享相同的非常通用的异常。 – Joe

回答

3

我不知道为什么,但这个固定的bug:

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) { } 

我试图调试在异常情况发生,我想设置一个断点集合更改时。订阅该事件使例外消失。

+1

此解决方案似乎与此类评论相关的问题相关https://stackoverflow.com/questions/37166747/object-reference-not-set-to-an-instance-of-an-object-in-presentationframework#comment75550113_37171952:通过订阅事件,您可以保留对CollectionViewSource的引用并防止垃圾收集。 –

0

我花了很长时间,试图调试System.Windows并无处可寻,欢迎您尝试。

就将至少起作用的创可贴解决方法而言,from my question我发现new CollectionViewSource会导致问题,而CollectionViewSource.GetDefaultView则不会。

你说还有一两个问题与此:

1)我在修改的基础采集所有的时间和需要我的过滤器,通过使用ObservableCollections刷新

您可以解决这一点,听版本,然后更新您的过滤实例。

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

优雅?没有功能?是。

2)我正在使用GetDefaultView不支持的Live Shaping。

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

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

+1

稍后我会添加自己的答案。为每个CollectionView添加一个空的CollectionChanged事件处理程序解决了这个问题,我不知道为什么。 – marczellm