Click here to Skip to main content
15,867,594 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello everybody

I wanted to save the contents of a list (ObservableCollection) locally in a text file.

the whole thing is in WPF which had to be written without MVVM.

C#
<pre>using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;

namespace TimeRecorderPro
{
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {




        public DateTime startTime;
        public DateTime endTime;
        public Timer _currentTimer;

        public void Anfunk()
        {
            Timers.Add(_currentTimer);
            btnStart.Content = "Start";

        }

        void Löschen()
        {
            txtStart.Text = "";
            txtEnde.Text = "";

        }

        public void BemerkungEinfuegen(string str)
        {
            _currentTimer.Bemerkung = str;
        }



        private ObservableCollection<Timer> Timers;
        public MainWindow()
        {
            InitializeComponent();
            Timers = new ObservableCollection<Timer>
            { };
            lstNames.ItemsSource = Timers;


        }





        private void btnStart_Click(object sender, RoutedEventArgs e)

        {

            if ((string)btnStart.Content == "Start")
            {

                _currentTimer = new Timer();
                txtStart.Text = _currentTimer.Start.ToString("HH:mm:ss");
                btnStart.Content = "Ende";
            }
            else
            {

                _currentTimer.Ende = DateTime.Now;
                txtEnde.Text = _currentTimer.Ende.ToString("HH:mm:ss");
                _currentTimer.Dauer = _currentTimer.Ende - _currentTimer.Start;

                
                txtEnde.Text = _currentTimer.Ende.ToString("HH:mm:ss");

                

                Bemerkung bemerkungsdialog = new Bemerkung();
                bemerkungsdialog.Owner = this;
                bemerkungsdialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                bemerkungsdialog.ShowDialog();
                /*
                Bemerkung bemerkungsdialog = new Bemerkung(_currentTimer);
                bemerkungsdialog.Owner = this;
                bemerkungsdialog.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                bemerkungsdialog.ShowDialog();
                */



                Anfunk();
                Löschen();

            

             }
        
        }
            private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
                    {
                        e.Cancel = true;
                        this.Visibility = Visibility.Hidden;


                        string testtext = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/Zeitbuchung_" +      DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt";


                        var objWriter = new System.IO.StreamWriter(testtext);



                      



                      objWriter.WriteLine(Timers.ToString());


            }

        private void lstNames_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }

        
    }

    public class Timer
    {
        public Timer()
        {
            Start = DateTime.Now;
        }
        public DateTime Start { get; set; }
        public DateTime Ende { get; set; }
        public TimeSpan Dauer { get; set; }
        public string Bemerkung { get; set; }
    }

a new text file is created here, after that I thought the last loop iterate first, the outer loop iterates the items and the inner loop the clumns then to save the whole thing with the code in text file, I would be grateful for your answers like the code in this one Place had to look.





C#
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
                    {
                        e.Cancel = true;
                        this.Visibility = Visibility.Hidden;


                        string testtext = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/Zeitbuchung_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt";


                        var objWriter = new System.IO.StreamWriter(testtext);



                      



                      objWriter.WriteLine(Timers.ToString());


What I have tried:

I've included everything I've tried above
Posted
Updated 26-Nov-20 23:11pm
Comments
BillWoodruff 25-Nov-20 7:21am    
is there a reason you have to use plain-text, ot JSON ? imho, for Windows: so much easier to use DataContract Serialization ... which encourages you to write more maintainable code at relatively low expense ...

if you request, i'll post a code example.
MMazi 27-Nov-20 3:27am    
Thank you very much, can you post the code example?

Just to add to what TheRealSteveJudge has said, saving data in a text file really depends on what you want to do with it: if you purpose is to save it so that a user can read it later, then Steve's solution is fine.

But ... if you are saving it so you can read it back later and repopulate your data structures, then a "straight text" solution is suboptimal as it requires significant processing on your part to retrieve that data. A better solution for that would be to use a structured file formal such as CSV (can easily be imported to Excel for a user to read), XML, or - my prefered solution - JSON. None of these are particularly human readable, though they can be read and edited manually with a little practice, but they are much, much easier to process back into your application. For JSON, I'd recommend you look at the Newtonsoft.JSON NuGet package, where save and restore operations are a single line of code.
 
Share this answer
 
Comments
TheRealSteveJudge 25-Nov-20 7:05am    
5* for suggesting a machine readable data format.
First of all you must use a StreamWriter in order to write lines to a text file.
Then you must loop through the ObservableCollection in order to get the items.
Then you must format a string by using the properties of each item.
This could look like this:
C#
using (var sw = new StreamWriter(@"c:\temp\output.txt"))
{
	foreach (var timer in timers)
	{
		await sw.WriteLineAsync($"Start: {timer.Start:dd.MM.yyyy HH:mm:ss}" +
								$", Ende: {timer.Ende:dd.MM.yyyy HH:mm:ss}" +
								$", Dauer: {timer.Dauer}" +
								$", Bemerkung: {timer.Bemerkung}");
	}}
}

Maybe you wonder about WriteLineAsync.
This will not block the User Interface while writing the file.

The mixture of String Interpolation and String Concatenation was suggested by Resharper.
It was a one liner before. I did not see it...
In order to get a better source code readability it is a good idea to use a so called StringBuilder.
Another good idea is to refactor the code in order to have a method which cares about writing the files.
You can pass an object that implements IEnumerable.
The ObservableCollection also derives from it.
This will allow you to pass a List as well.

Please have a look at this snippet:
C#
private static void WriteListToFile(IEnumerable<Timer> timers, string path)
{
	var sb = new StringBuilder();
	var delimiter = " ";

	using (var sw = new StreamWriter(path))
	{
		foreach (var timer in timers)
		{
			sb.Clear();

			sb.Append($"Start: {timer.Start:dd.MM.yyyy HH:mm:ss}");
			sb.Append(delimiter);
			sb.Append($"Ende: {timer.Ende:dd.MM.yyyy HH:mm:ss}");
			sb.Append(delimiter);
			sb.Append($"Dauer: {timer.Dauer}");
			sb.Append(delimiter);
			sb.Append($"Bemerkung: {timer.Bemerkung}");

			sw.WriteLine(sb.ToString());
		}
	}
}

The output in this example would be this:
Start: 25.11.2020 11:02:52, Ende: 25.11.2020 11:02:52, Dauer: 01:00:00, Bemerkung: A
Start: 25.11.2020 11:02:52, Ende: 25.11.2020 11:02:52, Dauer: 02:00:00, Bemerkung: B

Another suggestion: You could rename your Timer class to something more meaningful as it is confusing. There are already at least two other Timer classes in the .Net Framework.

For the sake of completeness here is a way to serialize your list to a JSON File by using Newtonsoft.Json Json.NET - Newtonsoft[^]
C#
private static void WriteObjectToJsonFile(object obj, string path)
{
	var json = JsonConvert.SerializeObject(obj, Formatting.Indented);

	using (var sw = new StreamWriter(path))
	{
		sw.Write(json);
	}
}

As you can see this approach is far more elegant than writing a serializer by yourself.
You can pass any object and it will be written as JSON.
For your class it would look like this:
[
  {
    "Start": "2020-11-26T09:12:38.0565577+01:00",
    "Ende": "2020-11-26T10:12:38.0565577+01:00",
    "Dauer": "01:05:22",
    "Bemerkung": "A"
  },
  {
    "Start": "2020-11-26T09:12:38.0565577+01:00",
    "Ende": "2020-11-26T11:12:38.0565577+01:00",
    "Dauer": "01:02:43",
    "Bemerkung": "B"
  }
]

A JSON file can easily deserialized and thus be understood by your application without the need of complicated parsing.
 
Share this answer
 
v3
Comments
BillWoodruff 25-Nov-20 7:26am    
voted #3 And then, if the OP wants to re-build the List from the text file, they'll have to write a complex parser. .NET's serializers are useful to avoid exactly this kind of re-inventing the wheel.
TheRealSteveJudge 25-Nov-20 7:42am    
Thank you! But the OP asked exactly this: "Save a list to a text file".
He did not ask for a sophisticated solution as we would think of.
BillWoodruff 25-Nov-20 8:28am    
for me, a #3 is not a down-vote. there is often a fine-line between what a QA poster wants, and, what they will probably need in the future. since the entire state of the observable collection can be so easily saved/re-instanced with a relatively small effort ... i prefer serialization to XML using DataContract/DataMember ... thus making writing a hand-rolled parser not necessary: imho, that's the direction i think the OP should be made aware of.

there is a "mystery" here: why did the OP use Observable Collection ... the code shows no use of its event-raising facilities.
TheRealSteveJudge 25-Nov-20 9:30am    
I know, 3* ist just a neutral vote. Never mind.
In my opinion it is not necessary to frighten a beginner who does not now how to save a file on disk with a perfect and highly sophisticated solution.
This is not what the OP asked for.
Your suggestions make sense seen from a professional and experienced perspective but may probably not be understood.
BTW the usage of an ObservableCollection in a non MVVM scenario makes me wonder as well.
BillWoodruff 26-Nov-20 1:24am    
Hi Steve, I have raised my vote on your solution to #4: I know your intention is to help the OP, and, you took your time to write code relevant to what the OP asked for.

From my experience teaching programming, and, what I see in the code the OP posted, I do not see a "beginner."

"In my opinion it is not necessary to frighten a beginner who does not now how to save a file on disk with a perfect and highly sophisticated solution." This kind of projective identification onto a vague context is your personal experience speaking.

You can improve your solution by using StringBuilder, and, by explaining your use of the advanced ASync facilities.
i have to say that i'm not a bloody beginner, i'm in a retraining course and am learning why i used an observablecollection because the first thing that struck me is that it is true that the data from a tool can be written in text much more effectively to save. thank you
 
Share this answer
 
Comments
Richard MacCutchan 27-Nov-20 5:14am    
This is not a Solution, and it is far from obvious who your are talking to.
MMazi 27-Nov-20 6:54am    
Hi Richard, Please excuse me, I wrote in the wrong field and I am correct I did not mention who I wrote with, I will pay attention to it in the future. thank you very much and wish you a nice day
MMazi 27-Nov-20 7:01am    
i mean ,that is correct what you wrote :)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900