Jooj
Jooj

Reputation: 101

Instantiating ViewModel in XAML raises error: "String was not recognized as a valid DateTime"

I’m trying to write my first WPF project, using EF, and implementing MVVM.

(It's a project for CRUD of employees' requests to get permission to attend some particular course. The employees' ID, name, dept are fetched from a text file, to be displayed in a combobox. The project should save all relevant data (courses, employees who made a request, requests) in a DB)

When I instantiate a ViewModel from my View, as follows:

<Window.Resources>
    <local:MainViewModel x:Key="myMainViewModel"/>
</Window.Resources>

…VS2012 reports this error (at the 2nd line of XAML above):

Error   String was not recognized as a valid DateTime.

So, it seems VS2012 has a problem initialising my ViewModel. The databindings, however, do work somehow. The project, as it stands, seems to run just fine. The Employees from the text file are properly listed in the combobox.

My ViewModel’s constructor fetches data to be stored in a property’s field:

public MainViewModel()
{
    IList<Employee> employees = GetEmployees();
    _employeesCollectionView = CollectionViewSource.GetDefaultView(employees);
}

The data are fetched from a text file (which works fine).

The error, however, is not shown after changing the constructor’s implementation as follows, and running the project again:

public MainViewModel()
{
    _employeesCollectionView = new CollectionView(new List<Employee>());
}

The Employee class has no properties (or fields) of the DateTime type.

I’ve tried removing the Employee class from my EF DbContext, but still get the DateTime error, so i suppose EF has nothing to do with that.

I’ve tried commenting out the sole control that has a binding to the ViewModel’s property Employees (in which the fetched employee data are stored).

So, now I've run out of ideas on how to fix this. Searching the web didn't help. Perhaps you can? I'd be most grateful if you do.


UPDATE: Here's the code of the method that seems to be causing my trouble: GetEmployees, and the DataLoader object it uses:

   public IList<Employee> GetEmployees()
    {
        DataLoader dataLoader = new DataLoader();
        dataLoader.LoadEmployeesFromPayroll();
        return dataLoader.Employees;
    }

namespace Bijscholingen
{
    public class DataLoader
    {
        private const string _PATH_OF_DATAFILE_FROM_PAYROLL = @"C:\Test.txt";
        public List<Employee> Employees { get; private set; }

        public DataLoader()
        {
            this.Employees = new List<Employee>();
        }

        public void LoadEmployeesFromPayroll()
        {
            StreamReader streamReader = null;
            try
            {
                streamReader = new StreamReader(_PATH_OF_DATAFILE_FROM_PAYROLL, System.Text.Encoding.UTF7);
            }
            catch
            {
                MessageBox.Show("File not found");
                return;
            }

            this.Employees.Clear();
            //skip first line of text file (contains headers)
            streamReader.ReadLine();
            while (!streamReader.EndOfStream)
            {
                //read textfile line byline
                string line = streamReader.ReadLine();
                string[] fields = line.Split(';');

                DateTime dateValue = DateTime.MinValue;
                if (DateTime.Parse(fields[6]) <= DateTime.Now &&
                    ((DateTime.TryParse(fields[7], out dateValue) && dateValue >= DateTime.Now) || fields[7].Equals(""))
                    )
                {
                    int idToFind = Int32.Parse(fields[0]);
                    Employee loadedEmployee = this.Employees.Find(e => e.EmployeeID.Equals(idToFind));
                    if (loadedEmployee != null)
                    {
                        loadedEmployee.EmployeeDeptsFromPayroll.Add(fields[5]);
                    }
                    else
                    {
                        List<string> deptsList = new List<string>();
                        deptsList.Add(fields[5]);
                        Employee employee = new Employee(Int32.Parse(fields[0]), fields[2], fields[4], fields[3], deptsList);

                        this.Employees.Add(employee);
                    }
                }
            }
            streamReader.Close();
            this.Employees = this.Employees.OrderBy(e => e.ToString()).ToList<Employee>();
        }
    }
}

The text file this method parses, has valid date values in it's last 2 fields. The last field is empty in some records (which is why i used TryParse for that field).

Upvotes: 0

Views: 483

Answers (1)

Will Custode
Will Custode

Reputation: 4604

Your call to GetEmployees must be throwing an exception on a convert from string to DateTime. I would look into that. When instantiating an object in Xaml (as you are doing by the call to <local:MainViewModel x:Key="myMainViewModel" />) any exceptions raised during construction will crash it. This is, as you can guess, because the UIControl you are instantiating that in turn tries to instantiate this object doesn't know whether or not the rest of the page depends on this object. There's no mechanism for a try-catch in Xaml.

Best practice is to avoid data-loading during construction so, at bare minimum, the page displays. Then, on the Loaded event for the control that instantiated this ViewModel, call an Initialize method on the ViewModel, which can then be try-catch'd and appropriately handled.

Upvotes: 1

Related Questions