-2

i'm a newbie in MVVM, I have a Model.cs which contains a few property of 'ID' and 'PositionName' and i got View.cs which contains DataGrid with SelectedItems={Binding Items} and ItemSource={Binding Position} and a button with a Command={Binding SHowEdits} after clicking that i encountered a NullReference error at 'Items.PositionName == null '.
here's my code.

ViewModel.cs

class PositionVM : INotifyPropertyChanged
{
    private ObservableCollection<PositionModel> _position;
    private PositionModel _items;
    private ICommand _showedits;
    public ObservableCollection<PositionModel> Position
    {
        get
        {
            return _position;
        }
        set
        {
            _position = value;
            NotifyProperty("Position");
        }
    }
    public PositionModel Items
    {
        get
        {
            return _items;
        }
        set
        {
            _items = value;
            NotifyProperty("Items");
        }
    }
    public ICommand ShowEdits
    {
        get
        {
            if (_showedits == null)
                _showedits = new ShowEdit();
            return _showedits;
        }
        set
        {
            _showedits = value;
        }
    }
    public PositionVM()
    {
        Position = new ObservableCollection<PositionModel>();
        Position.Add(new PositionModel()
        {
            ID = 1,
            PositionName = "asd"
        });
    }
    public void ShowEditDialog()
    {
        if (Items.PositionName == null)
        {
            MessageBox.Show("ERROR");
        }
        else
        {
            PositionView view = new PositionView();
            Data.ID = view.txtid.Text;
            var z = new PositionView();
            z.ShowDialog();
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyProperty(String info)
    {
        if(PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
}

Why am i getting this error? and How can i avoid it? Thanksss

sakusa1
  • 27
  • 9

2 Answers2

0

Since this line

Items.PositionName == null

throws a null reference exception, it's clear that Items is null.

Why Items is null?

The Items property is defined as below:

public PositionModel Items
{
    get
    {
        return _items;
    }
    set
    {
        _items = value;
        NotifyProperty("Items");
    }
}

When you try to set the value of PositionModel a call to the getter (get { return _items; })is done, in order you get a reference to the object that _items point to. The value you get is null. That means that either the setter has not been called, in order _items to be initialized with a value or it has been initialized but later on another part of your code has set it to null.

Looking through your code, we see the constructor of your class:

public PositionVM()
{
    Position = new ObservableCollection<PositionModel>();
    Position.Add(new PositionModel()
    {
        ID = 1,
        PositionName = "asd"
    });
}

Apparently, the Items are not initialized there. So Items has the default value for a reference type, null...

Christos
  • 53,228
  • 8
  • 76
  • 108
0

I think your problem with ICommand. Try to do it as property:

public ICommand ShowEditsCommand { get; set; };

And of course you need create it. I use my Command class for it, you can use it too on first time, it's pretty simple:

/// <summary>
/// Relay implementation of ICommand.
/// </summary>
public class RelayCommand : ICommand
{
    private Action execute;

    private Predicate<object> canExecute;

    private event EventHandler CanExecuteChangedInternal;

    public RelayCommand(Action execute)
        : this(execute, DefaultCanExecute)
    {
    }

    public RelayCommand(Action execute, Predicate<object> canExecute)
    {
        if (execute == null)
        {
            throw new ArgumentNullException("execute");
        }

        if (canExecute == null)
        {
            throw new ArgumentNullException("canExecute");
        }

        this.execute = execute;
        this.canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            CommandManager.RequerySuggested += value;
            this.CanExecuteChangedInternal += value;
        }

        remove
        {
            CommandManager.RequerySuggested -= value;
            this.CanExecuteChangedInternal -= value;
        }
    }

    public bool CanExecute(object parameter)
    {
        return this.canExecute != null && this.canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        this.execute();
    }

    public void OnCanExecuteChanged()
    {
        EventHandler handler = this.CanExecuteChangedInternal;
        if (handler != null)
        {
            handler.Invoke(this, EventArgs.Empty);
        }
    }

    public void Destroy()
    {
        this.canExecute = _ => false;
        this.execute = () => { return; };
    }

    private static bool DefaultCanExecute(object parameter)
    {
        return true;
    }
}

After this you need to initialize it in your viewmodel constructor and bind it to method:

ShowEditsCommand = new RelayCommand(ShowEdits);

Where ShowEdits is your methods that you need run when command call:

public void ShowEdits()
{
 // do something here
}
O.Holubkow
  • 16
  • 1