Sunday, July 22, 2018

c# - NullReference Exception in PresentationFramework



Below is a minimal example, I couldn't possibly reduce it any more than this.




I create a live filtered CollectionView in the ViewModel like this:



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 : ObservableCollection
{
public ObservableCollection2() : base() { }
public ObservableCollection2(T[] t) : base(t) { }

public void AddRange(IEnumerable collection)
{
foreach (var i in collection)
{
Items.Add(i);
}
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}


class MainWindow: ViewModelBase
{
public MainWindow() { }
private ObservableCollection2 people = new ObservableCollection2();
public ObservableCollection2 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;
}
}
}
}


The GUI has a button that modifies a Person object in the People collection:




        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">












I load the data from an XML file like this:



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;
}
}
}


and the XML file is this:








Person1
0


Person2
0






When I click the button once or twice, I get a NullReference exception. There is no inner exception. The exception does not arise in my code, but in framework code, so it does not show the source, I cannot find out which object is null and where the exception comes from. I didn't manage to set up "stepping into .NET sources", it still tells me that there is no source available.



Here's a stack trace:




at System.Windows.Data.ListCollectionView.RestoreLiveShaping() 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)
at System.Windows.Threading.DispatcherOperation.InvokeImpl() at
System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(Object
state) at
System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
preserveSyncCtx) at

System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
preserveSyncCtx) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state) at
MS.Internal.CulturePreservingExecutionContext.Run(CulturePreservingExecutionContext
executionContext, ContextCallback callback, Object state) at
System.Windows.Threading.DispatcherOperation.Invoke() at
System.Windows.Threading.Dispatcher.ProcessQueue() at
System.Windows.Threading.Dispatcher.WndProcHook(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)
at
System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority

priority, TimeSpan timeout, Delegate method, Object args, Int32
numArgs) at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32
msg, IntPtr wParam, IntPtr lParam) at
MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg) at
System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame
frame) at
System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
at System.Windows.Application.RunDispatcher(Object ignore) at
System.Windows.Application.RunInternal(Window window) at
System.Windows.Application.Run(Window window) at

System.Windows.Application.Run() at AntiBonto.App.Main() in
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(String assemblyFile,
Evidence assemblySecurity, String[] args) at
Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at
System.Threading.ThreadHelper.ThreadStart_Context(Object state) at
System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
preserveSyncCtx) at

System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state, Boolean
preserveSyncCtx) at
System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state) at
System.Threading.ThreadHelper.ThreadStart()



Answer



I have no idea why, but this fixed the 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) { }


I was trying to debug where the exception happens, and I wanted to set a breakpoint when the collection changes. Subscribing to the event made the exception go away.


No comments:

Post a Comment

plot explanation - Why did Peaches' mom hang on the tree? - Movies & TV

In the middle of the movie Ice Age: Continental Drift Peaches' mom asked Peaches to go to sleep. Then, she hung on the tree. This parti...