-1

How can I save and load ObservableCollection in MVVM ListView. The error is below..

An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll

Additional information: Database_MVVM.Model.UserData cannot be serialized because it does not have a parameterless constructor.

In my MainViewModel

public ObservableCollection<UserData> _userDataCollection = new ObservableCollection<UserData>();

public ObservableCollection<UserData> UserDataCollection
        {
            get { return _userDataCollection; }
            set { _userDataCollection = value; }
        }

public ICommand SaveCommand
        {
            get
            {
                if (saveCommand == null)
                {
                    saveCommand = new DelegateCommand(Save);
                }
                return saveCommand;
            }
        }

private void Save()
{
    XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<UserData>));

   using (var sw = new StreamWriter("output.txt"))
   {
       serializer.Serialize(sw, UserDataCollection);
       sw.Close();
   }
}

my Model

public class UserData
    {
        #region Declarations

        private string _theEnteredData;
        private string _theRandomData;

        public UserData(string theEnteredData, string theRandomData)
        {
            this._theEnteredData = theEnteredData;
            this._theRandomData = theRandomData; 
        }
        #endregion

        #region Properties
        public string theEnteredData
        {
            get { return _theEnteredData; }
            set { _theEnteredData = value; }
        }

        public string theRandomData
        {
            get { return _theRandomData; }
            set { _theRandomData = value; }
        }
        #endregion
    }

In My Command, I create DelegateCommand.cs

 public class DelegateCommand : ICommand
    {
        private readonly Action _action;

        public DelegateCommand(Action action)
        {
            this._action = action;
        }

        public bool CanExecute(object parameter)
        {
            return true;
        }

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

        public event EventHandler CanExecuteChanged
        {
            add
            {
            }
            remove
            {
            }
        }

Once I save the item in listview will automatically clear. Load the save file(txt file) and load it without using openfiledialogbox and with openfiledialog box.

I try using streamwriter and foreach loop to save it as text file but I failed I'm just new to MVVM and still trying to learn it.

LuluErwin
  • 39
  • 1
  • 9
  • 1
    Hope this helps: [Save/Load an Observable collectin of object to an XML file][1] [How to write an observable collection to a txt file?][2] [1]: http://stackoverflow.com/questions/1194931/what-is-the-easiest-way-to-save-an-observable-collectin-of-object-to-an-xml-file [2]: http://stackoverflow.com/questions/18834698/how-to-write-an-observable-collection-to-a-txt-file – Quan Nguyen Aug 19 '15 at 06:52
  • 1
    You know, exceptions are not here to punish us, they are here to tell us what's wrong and why. You need to **read** them. Look at inner exceptions as well. Think about what they say. When they tell you something simple and direct, listen to them and act accordingly. –  Aug 19 '15 at 18:40

3 Answers3

1

As the exception states: UserData does not have a default constructor.

The serializer uses the default constructor to create instances so if it is missing the serializer can't create objects.

Add a default constructor:

public class UserData
{
    #region Declarations

    private string _theEnteredData;
    private string _theRandomData;

    public UserData()
    {
    }

    public UserData(string theEnteredData, string theRandomData)
    {
        this._theEnteredData = theEnteredData;
        this._theRandomData = theRandomData; 
    }
    #endregion

    #region Properties
    public string theEnteredData
    {
        get { return _theEnteredData; }
        set { _theEnteredData = value; }
    }

    public string theRandomData
    {
        get { return _theRandomData; }
        set { _theRandomData = value; }
    }
    #endregion
}
Emond
  • 50,210
  • 11
  • 84
  • 115
0

Can you try this set up in your mainViewModel?

public ObservableCollection<UserData> _userDataCollection = new ObservableCollection<UserData>();
public ObservableCollection<UserData> UserDataCollection
{
get { return _userDataCollection; }
set
{
_userDataCollection = value;
RaisePropertyChanged(() => UserDataCollection);
}
}

public ICommand SaveCommand
{
get
{
//Bind UserDataCollection to your List View
LoadDataToListView();
}
}

private void LoadDataToListView()
{
using (var sw = new StreamWriter("output.txt"))
{
//load in UserDataCollection your data from textfile in here
 sw.Close();
}
return UserDataCollection ;
}

Just load you data in your UserDataCollection from your text file and bind it to your list view. You will use the same for your Model. This works fine on me. I hope that I help you. Good luck.

Update for your model

public class UserData
    {
        #region Declarations

        private string _theEnteredData;
        private string _theRandomData;

        public UserData(string theEnteredData, string theRandomData)
        {
            theEnteredData = theEnteredData;
            theRandomData = theRandomData; 
        }
        public UserData(){}
        #endregion

        #region Properties
        public string theEnteredData
        {
            get { return _theEnteredData; }
            set { _theEnteredData = value; }
        }

        public string theRandomData
        {
            get { return _theRandomData; }
            set { _theRandomData = value; }
        }
        #endregion
    }
yhAm
  • 443
  • 6
  • 11
  • yham, can you tell me where is the method stub of LoadDataToListView(); Thank you. – LuluErwin Aug 19 '15 at 12:45
  • also I got an error, my BaseViewModel **Cannot convert lambda expression to type 'string' because it is not a delegate type**. – LuluErwin Aug 19 '15 at 13:00
  • @LuluErwin, About the error, can you try to load first your data in a data table? and then load it to your collection. – yhAm Aug 20 '15 at 01:51
-1

XmlSerializer takes an object and converts it to xml which you can save to a text file. It can then be deserialized when needed.

    public void SaveToFile()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<UserData>));

        using (var sw = new StreamWriter("output.txt"))
        {
            serializer.Serialize(sw, UserDataCollection);
            sw.Close();
        }

    }

    public void LoadFromFile()
    {
        XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<UserData>));

        using (Stream reader = new FileStream("output.txt", FileMode.Open))
        {
            // Call the Deserialize method to restore the object's state.
            UserDataCollection = (ObservableCollection<UserData>)serializer.Deserialize(reader);
        }
    }
nickm
  • 1,775
  • 1
  • 12
  • 14
  • What is your error? It isn't clear where exactly your problem is. – nickm Aug 19 '15 at 07:31
  • Why is this downvoted? It answered the original question and offers a solution to save the collection to a text file. – nickm Aug 20 '15 at 02:02