-1

I have a picture that everything was working yesterday, but I also remember this error coming up before. I have surrounded:

                this.MainDataTable.DefaultView.RowFilter =
                  $"YRNRO LIKE '{this.YRNROSearchKey}*'" +
                  $"AND HAKUNIMI LIKE '{this.HAKUNIMISearchKey}*'" +
                  $"AND KONSERNI LIKE '{this.GROUPSearchKey}*'" +
                  $"AND LY LIKE '{this.BUSINESSIDSearchKey}*'" +
                  FIANDSEBoolquery + ACTIVEBoolquery;

With try & catch and it was working, but now I am getting the same error again, even with try & catch at the place.

I have WPF DataGrid (MVVM) with data in and CheckBoxes used as filters. If I comment out setting CheckBoxes "checked" during load time, everything works fine. However setting them to true is giving an error.

MainWindow.xaml.cs:

    public MainWindow()
    {
        InitializeComponent();

        _ = CheckForVPNConnectionTimeToTime();

        NetworkChange.NetworkAvailabilityChanged += OnNetworkAvailabilityChanged;
        var isAvailable = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
        OnNetworkAvailabilityChanged(isAvailable);

        // Commenting two lines below help to avoid errors
        // How to get it working with setup like this
        // when CheckBoxes are checked by default?
        ActiveCustomer.IsChecked = true;
        OnlyFIandSE.IsChecked = true;
    }

ViewModel_Main.cs:

using System.ComponentModel;
using System.Data;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;

namespace Inspector_FilterTest
{
    class ViewModel_Main : INotifyPropertyChanged
    {
        public ICommand LoadMainTableDataCommand => new RelayCommand(async param => await ExecuteLoadMainTableDataAsync());

        private DataTable mainDataTable;

        public DataTable MainDataTable
        {
            get => this.mainDataTable;
            set
            {
                this.mainDataTable = value;
                OnPropertyChanged();

                // Set the DataTable filter expression
                EnableRowFiltering();
            }
        }

        ...

        // Binding checkbox FIANDSE Bool
        private bool _FIANDSEBool;
        public bool FIANDSEBool
        {
            get => this._FIANDSEBool;
            set
            {
                this._FIANDSEBool = value;
                OnPropertyChanged();

                // Refresh the DataTable filter expression
                EnableRowFiltering();
            }
        }

        // Binding checkbox ACTIVE Bool
        private bool _ACTIVEBool;
        public bool ACTIVEBool
        {
            get => this._ACTIVEBool;
            set
            {
                this._ACTIVEBool = value;
                OnPropertyChanged();

                // Refresh the DataTable filter expression
                EnableRowFiltering();
            }
        }

        ...

        public void EnableRowFiltering()
        {
            string FIANDSEBoolquery = FIANDSEBool ? " AND (YRNRO LIKE '6*' OR YRNRO LIKE '7*')" : string.Empty;
            string ACTIVEBoolquery = ACTIVEBool ? " AND KAYTOSSA='1'" : string.Empty;

            try
            {
                this.MainDataTable.DefaultView.RowFilter =
                  $"YRNRO LIKE '{this.YRNROSearchKey}*'" +
                  $"AND HAKUNIMI LIKE '{this.HAKUNIMISearchKey}*'" +
                  $"AND KONSERNI LIKE '{this.GROUPSearchKey}*'" +
                  $"AND LY LIKE '{this.BUSINESSIDSearchKey}*'" +
                  FIANDSEBoolquery + ACTIVEBoolquery;
            }
            catch (System.Exception)
            {
                // do nothing, just avoid application crash
            }
        }

        public async Task<DataTable> LoadMainTableDataAsync()
        {
            return await Task.Run(() =>
            {
                if (MainProcess.Customers.Rows.Count > 1)
                {
                    return MainProcess.Customers;
                }
                else
                {
                    MainProcess.MergedTable();

                    return MainProcess.Customers;
                }
            });
        }

        private async Task ExecuteLoadMainTableDataAsync()
        {
            if (MainProcess.CheckForVPNInterface())
            {

                this.HasProgress = true;

                this.MainDataTable = await LoadMainTableDataAsync();

                this.HasProgress = false;
            }
            else
            {
                string caption = "VPN connection missing";

                MessageBox.Show("Please, check your VPN connection!", caption,
                                 MessageBoxButton.OK,
                                 MessageBoxImage.Exclamation);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
          => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Error I am getting:

System.NullReferenceException: 'Object reference not set to an instance of an object.'

Inspector_FilterTest.ViewModel_Main.MainDataTable.get returned null.

Pointing at:

                this.MainDataTable.DefaultView.RowFilter =
                  $"YRNRO LIKE '{this.YRNROSearchKey}*'" +
                  $"AND HAKUNIMI LIKE '{this.HAKUNIMISearchKey}*'" +
                  $"AND KONSERNI LIKE '{this.GROUPSearchKey}*'" +
                  $"AND LY LIKE '{this.BUSINESSIDSearchKey}*'" +
                  FIANDSEBoolquery + ACTIVEBoolquery;
hatman
  • 1,620
  • 10
  • 30

1 Answers1

0

When the constructor is invoked, MainDataTable is still null. It's only initialized when LoadMainTableDataAsync is called.
The constructor sets ActiveCustomer.IsChecked = true; which binds to the ViewModel_Main.ACTIVEBoolquery. This property calls EnableRowFiltering. This method accesses the uninitialized MainDataTable: this.MainDataTable.DefaultView.RowFilter.

Some solutions:

Initialize the MainDataTable from the constructor:

// Please read: Names of Classes, Structs, and Interfaces
class ViewModel_Main : INotifyPropertyChanged
{
  public ViewModel_Main()
  {
    // Alternatively call LoadMainTableDataAsync(). 
    // But take care not to execute long-running operations from the constructor.
    this.MainDataTable = new DataTable();
  }
}

Or/and perform a null-check before accessing MainDataTable:

public void EnableRowFiltering()
{
  if (this.MainDataTable == null)
  {
    return;
  }

  // Please read: Capitalization Conventions
  string FIANDSEBoolquery = FIANDSEBool ? " AND (YRNRO LIKE '6*' OR YRNRO LIKE '7*')" : string.Empty;
  string ACTIVEBoolquery = ACTIVEBool ? " AND KAYTOSSA='1'" : string.Empty;

  this.MainDataTable.DefaultView.RowFilter =
    $"YRNRO LIKE '{this.YRNROSearchKey}*'" +
    $"AND HAKUNIMI LIKE '{this.HAKUNIMISearchKey}*'" +
    $"AND KONSERNI LIKE '{this.GROUPSearchKey}*'" +
    $"AND LY LIKE '{this.BUSINESSIDSearchKey}*'" +
    FIANDSEBoolquery + ACTIVEBoolquery;
}

Microsoft Docs: Capitalization Conventions, Names of Classes, Structs, and Interfaces or generally Naming Guidelines.

As a note: catching the general Exception is very bad practice. Only catch specific exceptions, and only those you really can handle. Logging an exception is not handling it.
Catching an exception without handling it, is a very bad practice. Instead of swallowing exceptions, prevent them. A NullReferenceException can be prevented by performing a null-check before referencing the instance or by using the ? Null-conditional operator. A IndexOutOfRangeException can be prevented by checking index bounds before accessing the field.

Swallowing exception will lead to bugs, as you/the developer won't get notified about erroneous code. The application may be in an unpredictable state producing unpredictable results. An account software that swallows conversion exceptions of currency may produce wrong balance. Instead let the application crash, investigate the source of the crash and fix it. This leads to a robust application. Microsoft Docs: Best practices for exceptions

BionicCode
  • 13,277
  • 2
  • 17
  • 33