2016-05-23 58 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