Click here to Skip to main content
14,937,163 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.
   
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.
   
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.
TheRealSteveJudge 26-Nov-20 2:19am
   
Hi Bill,
thank you again for your encouraging comments and suggestions and the upvote as well!
The term "beginner" was not meant to insult the OP.
A better would have been "less experienced developer".
I like the term "Projective Identification" as I indeed was a beginner as well and did not see the wood for the trees and was intimidated sometimes when asking the experts for help in the company I worked.
They sometimes went above and beyond what I was asking for.
I will improve my solution according to your suggestions.
BillWoodruff 27-Nov-20 0:09am
   
Hi Steve, I often think of CodeProject as a school where I learn from my peers and mentors ... but, being human :), I sometimes have to struggle to reach "beginner's mind."

You might enjoy this comparison of different techniques for composing/interpolating strings:

https://dotnetcoretutorials.com/2020/02/06/performance-of-string-concatenation-in-c/

cheers, Bill
TheRealSteveJudge 27-Nov-20 2:32am
   
fyi: this was an eye opener for me:

https://codewithshadman.com/c-stringformat-and-stringbuilder/

in terms of understanding the internals of StringFormat, and making me aware of the AppendFormat method of StringBuilder.
TheRealSteveJudge 27-Nov-20 5:06am
   
Who did change my reply?
I did not write this.
MMazi 27-Nov-20 4:36am
   
Thank you very much for the answers, true, my job was about saving the data from the timer in a text
of course, when it comes to using the data again, you even have to use json and co.
I will try json after completing this task. Thanks again

TheRealSteveJudge 27-Nov-20 5:08am
   
You're welcome.
If you like our answers please accept them.
Thank you!
MMazi 27-Nov-20 5:11am
   
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
MMazi 27-Nov-20 5:15am
   
ok i do but i ended up using this code
string filename = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "/Zeitbuchung_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".txt");

File.WriteAllLines(filename, Timers.Select(x => $"Start= {x.Start}, Ende= {x.Ende}, Dauer= {x.Dauer}, Bemerkung= {x.Bemerkung}"));
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
   
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