This question already has an answer here:
-
What is a NullReferenceException, and how do I fix it?
31 answers
I have WPF application where I am following MVVM. I have a class called Session as follows:
Session.cs
public class Session:ObservableCollection<Session>
{
public int value { get; set; }
public string name { get; set; }
}
public class CustomSession:DependencyObject
{
public static readonly DependencyProperty SessionCollectionProperty =
DependencyProperty.Register("SessionCollection", typeof(Session), typeof(CustomSession), new PropertyMetadata());
public Session SessionCollection
{
get { return (Session)GetValue(SessionCollectionProperty); }
set { SetValue(SessionCollectionProperty, value); }
}
}
I have ViewModel as follows:
ViewModel.cs
public class ViewModel:BindableBase
{
private ObservableCollection<Session> _sessions;
public ObservableCollection<Session> sessionsCollection
{
get { return _sessions; }
set { SetProperty(ref _sessions, value); }
}
public ViewModel()
{
sessionsCollection = allSessions();
}
public ObservableCollection<Session> allSessions()
{
CustomSession custom = new CustomSession();
custom.SessionCollection.Add(new Session() { name = "LocateSession", value = 10 }); //System.Null Reference Exception.
custom.SessionCollection.Add(new Session() { name = "TrackSession", value = 20 });
custom.SessionCollection.Add(new Session() { name = "MonitorSession", value = 25 });
custom.SessionCollection.Add(new Session() { name = "MassSnapshot", value = 18 });
custom.SessionCollection.Add(new Session() { name = "MassContinuous", value = 9 });
return custom.SessionCollection;
}
}
I have a UI where I want to bind this Observable Collection. Whenever I try to add in an item like
custom.SessionCollection.Add(new Session() { name = "LocateSession", value = 10 });
I get Null Reference exception. I want to populate the ObservableCollection from the ViewModel. How do I do it. Please help.
I don't think that not initializing the _sessions
field caused the null error. You have never directly used that field(or property). It was only assigned so can't cause null exception.
Your problem was that your DependencyProperty SessionCollection
doesn't have a default value. So when line custom.
SessionCollection.Add(..)
gets executed you get a null exception. AS SessionCollection
will have null default value.
Try to change your property like this(In PropertyMetadata constructor give a default value, as I have given a new object (new Session())):
public static readonly DependencyProperty SessionCollectionProperty =
DependencyProperty.Register( "SessionCollection"
, typeof(Session)
, typeof(CustomSession)
, new PropertyMetadata(new Session())
);
public Session SessionCollection
{
get { return (Session)GetValue(SessionCollectionProperty); }
set { SetValue(SessionCollectionProperty, value); }
}
See below where the exception occurs:
First of all your Null reference exception will go away if you follow the correct mvvm approach which i'll describe (partially) below
MODEL
Following MVVM
enforces that only you presentation layer knows about WPF. The exception i accept is the ObservableCollection
type
Your Session
model is fine with the ObservableCollection
property but I would call it Sessions
.
On the other hand i see no reason to have CustomSession
at all - try to remove it
public class Sessions:ObservableCollection<Session>
{
public int value { get; set; }
public string name { get; set; }
}
VIEW MODEL
It knows about your Sessions
type but it must not know about what is a DependencyObject
.
In the code below i often leave sessionsCollection
property as a getter only.
If I implement the set i always follow the INotifyPropertyChanged
pattern
public class ViewModel: BindableBase
{
private Sessions _sessions;
public Sessions sessionsCollection
{
get { return _sessions; }
}
public Session SelectedSession
{
get;set; //properly implemented with the INotifyPropertyChanged
}
public ViewModel()
{
sessionsCollection = allSessions();
}
public Sessions allSessions()
{
var custom = new Sessions();//notice this is already a collection
custom.Add(new Session() { name = "LocateSession", value = 10 }); //System.Null Reference Exception.
custom.Add(new Session() { name = "TrackSession", value = 20 });
custom.Add(new Session() { name = "MonitorSession", value = 25 });
custom.Add(new Session() { name = "MassSnapshot", value = 18 });
custom.Add(new Session() { name = "MassContinuous", value = 9 });
return custom;
}
}
VIEW
In the WPF simply bind some combobox, listbox, etc to the Sessions
property.
I don't have wpf right here so the syntax might be wrong.
<ListBox Items={Binding sessionsCollection} SelectedItem={Binding SelectedSession} />
I'd like to add that although the original question only referred to NRE it only happened because it was exposing DependencyObject in the wrong scope. I truly believe my refactoring helps to understand the simplicity (and advantages) of MVVM
If you are trying to fill this from code (which I assume you do) the problem is that you never initialized _sessions
. So just do this simple code exchange:
// old
// private ObservableCollection<Session> _sessions;
// now
private ObservableCollection<Session> _sessions = new ObservableCollection<Session>();
If you do not initialize _sessions
it will have no object its referencing to. This is what the NULL
reference means. If you try to access it anyway you will run into an error because it does not know which object you mean.
Edit
I think I got confused with the different variables here. As mentioned in the comments this should actually not solve the problem as you are accessing a different property. However: The general problem stays the same (accessing a collection that has not been initialized). To solve that problem I would recommend the solution proposed by @Kylo-Ren