C# - wczytywanie listy z .txt do listbox'a

0

Witam,
Mam do zrealizowania prosty projekt w języku C#.
W skrócie o programie: tworzymy klasę z kilkoma polami. Obiekty tej klasy mają znaleźć się w listboxie - muszę więc stworzyć buttony typu dodaj/edytuj/usuń obiekt oraz zapis do pliku i wczytanie z pliku.

Takim przyciskiem realizuję zapis do pliku:

const string sPath = "save.txt";
            StreamWriter SaveFile = new StreamWriter(sPath);
            foreach (var item in listbox1.Items)
            {
                SaveFile.WriteLine(item);
            }

            SaveFile.Close();

            MessageBox.Show("Tekst.");

Taki natomiast kod mam w przycisku wczytaj:

            listbox1.DataSource = null;
            listbox1.Items.Clear();
            listbox1.DataSource = null;
            listbox1.Items.AddRange(File.ReadAllLines("save.txt"));

            MessageBox.Show("Tekst");

Jaki jest problem?
Zapis się realizuje.
Lista obiektów zostaje wczytana.
W momencie jednak, jak zaznaczę którykolwiek z wczytanych obiektów i zechcę go edytować - następuje problem i wywala program, błąd typu że nie można przekonwertować (normalnie edycja działa). Dodatkowo jak dodam nowy obiekt do listy, to wczytana lista znika i pojawia się wyłącznie dodany po wczytaniu listy obiekt.
Inny błąd -> Dodam powiedzmy 2 obiekty. Zapiszę je. Dodam obiekt X. Wczytam poprzednie (ten przed chwilą dodany obiekt X znika, pojawiają się tylko te wczytane). Dodam kolejny obiekt Y -> wczytane obiekty znikają, teraz na liście znajduje się dodany wcześniej obiekt X oraz przed chwilą dodany obiekt Y. Czy jest ktoś w stanie pomóc mi rozwiązać ten problem, proszę tylko wziąć pod uwagę, że jestem początkujący jeśli chodzi o programowanie i chętnie przyjmę łopatologiczne wskazówki. :D

0

Pokaż więcej kodu, kod klasy, jak edytujesz, dodajesz obiekt w listboxie? Niepotrzebne Ci to DataSource=null, do tego dwukrotnie.

0

Klasa prosta - kilka razy pole typu string/double/int z {get; set} (wiek, imię etc)

  • metoda przerobiona .Tostring() z return, który powoduje pokazanie w listboxie wpisanych wartości.

Dodawanie:

osoba = null;
            oknoDodaj = new OknoDodaj(this);
            oknoDodaj.ShowDialog();

            if (osoba!= null)
            {
                if (osoba.imie!= "" && osoba.imie!= null)
                {
                    listaObjektow.Add(osoba); // lista obiektów realizowana przez Arraylist
                    listbox1.DataSource = null;
                    listbox1.DataSource = listaProduktow;
                }
            }

Przycisk save z okienka oknoDodaj

if (osoba == null)
            {
                osoba = new Osoba();

                if (textboximie.Text != "" && textboximie.Text != null && textboxwiek.Text != "" && textboxwiek.Text != null)
                { 
                   osoba.imie= textboximie.Text;
                   osoba.wiek= int.Parse(textboxwiek.Text);
                   ...
                   hForm1.osoba = osoba;
                   Close();
                }
                else
                {
                        MessageBox.Show("Źle wprowadzone dane!");

                    osoba= null;
                }
0
listbox1.DataSource = listaProduktow;

A co to za listaProduktow?

0

A fakt, część musiałem zamienić, bo przerabiałem równolegle dwa programy jeden z klasą produktów, drugi osób. Błąd występuje z listaObjektow oczywiście, przepraszam za zamieszanie z tym. :D

0

Ułatw nam robotę i podaj w której linijce/linijkach krzyczy z błędami, a dodatkowo możesz poprawić formatowanie kodu :)

Jeżeli znikają Ci obiekty z listy, to pewnie walisz gdzieś listbox1.Items.Clear();

Przypatrz się, czy nie jest on w złym miejscu.

Dodatkowo

if (textboximie.Text != "" && textboximie.Text != null && textboxwiek.Text != "" && textboxwiek.Text != null)

https://msdn.microsoft.com/pl-pl/library/system.string.isnullorempty(v=vs.110).aspx

0

Edycję odłożyłbym na razie na bok, chciałbym przede wszystkim sprawić, żeby ta wczytana lista nie znikała po dodaniu nowego obiektu. Naprawić ten "inny błąd" z mojej pierwszej wiadomości.

Jeszcze co do usunięcia datasource = null, które zaproponowałeś, to jedno (to wyżej musi być), inaczej wczytanie wyrzuca błąd, że nie można wykonać .clear() gdy coś jest w datasource, więc je nulluje.

Mam takie wrażenie jakby to wczytanie powodowało wrzucenie objektów do listy ale tylko jako maska. Jak dodam coś do listy, to maska znika i jest to co było wcześniej + to co dodałem.

****Edit
Zmieniłem kod wczytywania na taki:

listaObjektow.Clear();
            listbox1.Items.AddRange(File.ReadAllLines("save.txt"));
            listaObjektow.AddRange(File.ReadAllLines("save.txt"));

            MessageBox.Show("Komunikat");

Problem został rozwiązany jeśli chodzi o to, że obiekty się usuwały.

Tak wygląda kod edycji:

            if (listbox1.SelectedItem == null)
            {
                MessageBox.Show("Brak objektu do edycji!");
            }
            else
            {
                osoba = (Osoba)listbox1.SelectedItem;
                oknoEdytuj = new OknoEdytuj(osoba);
                oknoEdytuj.ShowDialog();
                listbox1.DataSource = null;
                listbox1.DataSource = listaObjekow;
            }
  • przycisk zapisu:
if (textboximie.Text != "" && textboximie.Text != null && textboxwiek.Text != "" && textboxwiek.Text != null)
            {
                osoba.imie= textboximie.Text;
                osoba.wiek= int.Parse(textboxwiek.Text);
                Close();
            }
            else
{
//komunikat;
}

I teraz po wybraniu tego wczytanego obiektu i wybrania opcji edytuj wyrzuca taki błąd:

"System.InvalidCastException: „Nie można rzutować obiektu typu 'System.String' na typ 'Baza_Osob___Program_v1.Osoba'.”"
w linijce:
" osoba = (Osoba)listbox1.SelectedItem;"

Edit2@

Co do pytania o listeobjeków:
ArrayList listaObjektow = new ArrayList();

0

Jest dobrze haha, tylko pisałem tutaj, już dla jednej linijki nie będę otwierał visuala i kopiował :P
Co jest w txt? Plik powstaje w momencie zapisania obiektów. Więc trafia tam to, co wygeneruje przycisk zapisz (każdy obiekt w innej linii).

Tak mi się wydaje, że gdzieś brakuje mi przy wczytywaniu tworzenia obiektu - mam wrażenie, jakby ten tekst z pliku tekstowego trafiał do Arraylist listaobiektów nie jako obiekt, tylko jako nie wiem... ciąg znaków?

0

File.ReadAllLines zwraca Ci tablicę stringów, a nie Twój obiekt. Więc nie możesz później stringa z listboxa rzutować na swój obiekt.

0

Czyli w dobrym kierunku myślałem.. jakieś pomysły na rozwiązanie wczytywania, żeby każda linia w txt była wczytana jako obiekt?

0

Musisz przypisać odpowiednie linie do swoich pól obiektu, konwertując na odpowiedni typ, jeśli nie jest to string. Lub poczytaj sobie o serializacji.

0

No dobrze, tylko w jednej linii znajduje się każda zmienna danego obiektu np imię oraz wiek jest w jednej linii. Jak to rozdzielić, żeby imię wczytać do jednej zmiennej, a wiek do innej? Zapis linii do obiektu spowodowałby wczytanie wszystkich wartości do jednej zmiennej. Dodatkowo program ma przewidywać możliwość w zmiennych string trzymania oddzielonych spacją wartości, więc nie można wykorzystać spacji jako znaku, który przerwie wczytywanie i przejdzie do kolejnej zmiennej. Byłbym wdzięczny za pomoc w realizacji tego wczytywania.

PS. Program jest realizowany w Windows form, nie wpf.

0

Musisz mieć jakiś znak oddzielajacy poszczegolne dane albo stala ilosc znaków dla poszczegolnych wartości.
Czytasz cały plik do tablicy stringow. Potem lecisz po tablicy i dla każdego wiersza robisz jakiś substring czy split i wyciagasz odpowiednie wartosci do odpowiednich zmiennych czy pol klasy.

Program Ci nic nie przewidzi. To plik musi mieć odpowiedni format.

0

Łatwiej byłoby z serializacją. Możesz wykorzystać String.Split do odczytania.

foreach (var line in lines)
{
var variables = line.Split(' ');
person.Name = variables[0];
person.Surname = variables[1];
listPersons.Add(person);
}

To taki przykładowy kod, mało bezpieczne rozwiązanie, musisz sobie to zabezpieczyć i ewentualnie konwersja typów.

0

Hmm, bardziej prosto.

Czyli mam stworzyć tablicę:

string[] lines = new string[1000];

dopisać zawartość pliku(?)

lines = File.ReadAllLines("save.txt");

I na tej podstawie stworzyć taką pętlę jak wyżej?

Tak wygląda linia w .txt:

imię   -   wiek   -   inna_liczba   -   inny_string

A tak jeszcze poza tematem:
Okno edycji wywołuję konstruktorem, który mi w textboxy wstawia odpowiednie wartości:

                tbImie.Text = osoba.imie;

Posiadam również combobox, w którym wybieram czy dana osoba jest zatrudniona, czy nie jest. W klasie realizuję to jako char + metoda:

            string zatrudnienie;

            if (czyZatrudniona == 'Z')
            {
                zatrudnienie = "Osoba zatrudniona";
            }
            else
            {
                zatrudnienie = "Osoba niezatrudniona";
            }

Ogólnie wszystko działa, tylko zastanawia mnie, jak zrobić, by w okienku edycji nie pokazywało pustej zawartości, tylko stan zatrudnienia wybrany przy dodaniu (i wtedy można go sobie zmienić).

cbCzyZatrudniona.Text = osoba.czyZatrudniona.ToString();

Powyższe rozwiązanie tego nie robi.

0

Wystarczy, że zrobisz:

string[] lines = File.ReadAllLines("save.txt");

lub:

var lines = File.ReadAllLines("save.txt");

Plik .txt masz oddzielony spacjami, czy myślnikami?
Chcesz żeby w comboboxie pokazało się "Z", czy osoba zatrudniona?

0

Wyżej wstawiłem jak wygląda plik txt, jest to kilka spacji, myślnik, kilka spacji i kolejna zmienna. Powstaje to przez over tostringa() i jego return.

Chciałbym żeby pojawiło się osoba zatrudniona lub niezatrurniona, w zależności od tego co w okienku dodaj było przypisane do danej osoby. Już mam w cb do wyboru "osoba zatrudniona" i "osoba niezatrurniona", tylko chodzi o to, by podczas edycji w okienku była wybrana już wartość przypisana do danej osoby, bo teraz jest to puste i muszę ponownie wybrać z listy wartość. Dla texbtboxu np wiek realizuję to wyżej przedstawioną opcją w konstruktorze, ale dla comboboxa ten sposób nie działa.

0

Sorry, z tym splitem przyzwyczajenie z .net core.
Zrób sobie tak:

string[] separator = {" - "};
var variables = line.Split(separator,StringSplitOptions.None);
0

No i tak się teraz głowię.. łącznie mam cztery zmienne do wczytania. Przy variables[1] wyrzuca mi błąd, że indeks wykroczył poza tablicę..

1 użytkowników online, w tym zalogowanych: 0, gości: 1