problem pri ukladani obsahu z listview do suboru   otázka

VB.NET, .NET Tips

Dobrý den!

Používam tento kód na ukladanie do suboru:

Dim a As String
        a = ComboBox1.Text
        Dim myWriter As New IO.StreamWriter("C:\Users\Peter\Documents\" + a)

        For Each myItem As ListViewItem In ListView1.Items
            Dim myText As String = ""

            For Each mySubItem In myItem.SubItems
                myText += mySubItem.Text + " "
            Next

            myWriter.WriteLine(myText)
        Next

        myWriter.Close()

ale sposobuje to to že v danom riadku po niekolkatom uložení vzníkaju volne medzere a každým ukladaním pribudaju do každeho predošleho riadku to znamena že po 100 uložení bude 100x počet znakov volných medzier a to znemožnuje čítanie suboru nasledovnym kódom:

ListView1.Items.Clear()
        Dim a As String
        a = ComboBox1.Text

        Dim r As New IO.StreamReader("C:\Users\Peter\Documents\" + a)

        Do Until r.EndOfStream
            Dim myText As String = r.ReadLine
            Dim arr(150) As String

            Dim arrpointer As Integer = 0

            For Each line In myText.Split(" ", " ", " ", " ", " ", " ", " ")
                arr(arrpointer) = line
                arrpointer += 1
            Next

            Dim myItem As New ListViewItem(arr)
            ListView1.Items.Add(myItem)
        Loop
        r.Close()

potreboval by som upravou zapisovacej časti dosiahnuť to aby nehadzalo to do predošlích uloženych riadkov medzery.

Dakujem

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

První doporučuji pro příště používat StringBuilder místo "sčítání" textu. Je to rychlejší a méně paměťově náročné.

Dále jsem si všimnul, že máte zbytečné mezery v příkazu:

For Each line In myText.Split(" ", " ", " ", " ", " ", " ", " ")

Stačí:

For Each line In myText.Split(" ")

Ale nechápu problém. Zkuste napsat jak vypadá soubor s daty teď a jak by měl podle vás vypadat? Stačí krátký příklad.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ide o nasledovne. ak použijem na rozdelenie textu napriklad "," tak sa to rpejavy nasledovne:

Každný nový riadok bude mať napriklad 4 znaky a vypada to nasledovne:

1,2,3,4, - prve uloženie a nasledne pridam po otvorení suboru opať dlaší riadok takže:

1,2,3,4, , , , ,

1,2,3,4, - toto je druhe uloženie tretie vypada takto:

1,2,3,4, , , , , , , , ,

1,2,3,4, , , , , - tretie:

1,2,3,4, , , , , , , , , , , , ,

1,2,3,4, , , , , , , , ,

1,2,3,4, , , , ,

a ak nasledne sa snažím načítať subor generuje to chybu a musím dať vysoke číslo do arr(xy) aby to toelrovaloo počet znakov. Ten string builder ste schopny mi upraviť ten kód aby to fungovalo?

To množstvo "","" značí počet stlpcov kolko sa ma rozdeliť a načítať do tabulky.

dakujem

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pokusil jsem se načrtnou projekt, který řeší problém, který popisujete.

http://leteckaposta.cz/801518328

Místo mezery jako oddělovače jsem použil středník, protože mezera se můžu klidně objevit v názvu ListViewPoložky a pak by Vám ro rozhodilo načítání a ukládání. Stejně tak se tam může objevit středník, ale to by mělo být méně pravděpodobné. Ošetření této situace by řešení trochu zkomplikovalo, ale řešitelné to je tak, že se hodnoty uloží v závorkách (") a pokud hodnota obsahuje závorku, před uložením se zdvojí a při načtení "oddvojí". V pdostatě popisujete formát CSV (comma separated values), který to přesně takhle řeší.

Projekt jsem dělal ve Visual Studiu 2012, takže Vám možná v Express edici (neuvedl jste verzi Visual Studia, kterou používáte, předpokládám tedy Express) nepůjde SLN soubor otevřít. Zkuste tak otevřít přímo soubor VBPROJ a nebo si otevřete jednotlivé soubory a podívejte se přímo na jejich zdrojový kód.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

funguje to pekne ale sposobuje to chybu podobnu tomu predošlemu. Teraz každy uložením a znovu nahradením suboru to vypada takto:

1.uloženie:

a b c d e f

2.uloženie:

a a b c d e f

3. uloženie:

a a a b c d e f

4. uloženie:

a a a a b c d e f

Neviete prečo mi hádže stale znova tam listview item? a posuva mi v stlpcoch subiteimi?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Chyba byla ve způsobu, jakým jsem položky ukládal, jak uvidíte v rozdílu v novém a předešlém kódu.

http://leteckaposta.cz/434373649

ListViewItem.SubItems obsahuje i podpoložku, která reprezentuje text ListViewItemu. S Windows Form už jsem nějakou dobu nepracoval a zapomněl jsem na to a ukládání a otevírání jsem neotestovat pořádně. Nyní při ukládání nezapíšu text položky a pak podpoložek, ale pouze podpoložek, protože první z nich se jako text položky chová. Načítání se nemění, tam si konstruktor bere pole textů, které reprezentují text položky a jednotlivých podpoložek.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Super už je to ok Dakujem moc

Ešte jedna otazočka existuje nejaky jednoduchy sposob tlače obsahu listview do tabulky?

Dakujem

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Normálně by se to dělalo pomocí komponenty zvané PrintDialog. Tu byste zobrazil jako já v kódu třeba SaveFileDialog. Nejdřív byste ale musel vytvořit instanci objektu PrintDocument a hlídat jeho událost PrintPage, ve které byste zjistil, kolik položek se vejde na stránku z jejích rozměrů a ty byste vykreslil. Nastavil byste e.HasNextPages na True a čekal na další volání PrintPage, kde byste vykreslil další položky, dokud by Vám nedošly položky k vykreslení. Měl jsem to rozepsané, ale není to zrovna jednoduchá věc a není to na chvíli, tak jsem se rozhodl vydat se jinou cestou.

Přidal jsem na náš formulář komponentu WebBrowser, přidal jsem handler události DocumentCompleted, která se zavolá vždy, když se WebBrowser načte a tlačítkem pro tisk dělám to, že vytvořím HTML soubor, ve kterém je tabulka vytvořená z prvků v ListView a dosadím HTML do WebBrowseru. Ten zjistí změny vlastnosti, načte dokument, vyvolá událost DocumentCompleted a v té volám ShowPrintPreviewDialog(), ve kterém se dá nastavit tisk na šírku, na výšku a další podrobnosti tisku. WebBrowser se pak postará o samotné stránkování a celý tisk. WebBrowser můžete schovat pomocí vlastnosti Visible, kterou nastavíte na False. HTML generuji přímým zápisem XML do Visual Studia a <%= %> je speciální klauzule, do které jsem napsal LINQ příkaz, který iteruje prvky podobně, jako je tomu při ukládání.

http://leteckaposta.cz/381971864

Označte prosím mé příspěvky jako odpovědi, které a pokud odpovídají na Vaše dotazy.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Ako označím vaše odpovede?

Vo VB2008 ktory používam mi ten kód s HTML nevzalo je tam kopa chyb ale vo 2012 tke to funguje OK

Su tam nejake rozdiely?

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Mělo by tu být tlačítko "Odpovídá na dotaz" ( http://leteckaposta.cz/325201673 ), ale nevím, jestli jej jako neregistrovaný uživatel vidíte také.

Když se kouknete do toho kódu, vidíte, že jsem tam to XML zapsal přímo. To je myslím možné až od verze 2010, takže 2008ka to vnímá jako spoustu syntaktických chyb. Řešením je v té 2008ce nepsat přímo XML, ale poskládat to z textových řetězců. Opět byste mohl použít StringBuilder a napsat něco jako:

Dim builder As New StringBuilder()
builder.AppendLine("<html>")
builder.AppendLine("<body>")
builder.AppendLine("<table>")
For Each listViewItem As ListViewItem In ListView1.Items
  builder.AppendLine("<tr>")
  For Each listViewSubItem As ListViewSubItem In listViewItem.SubItems
    builder.AppendLine("<td>")
    builder.AppendLine(listViewSubItem.Text)
    builder.AppendLine("</td>")
  Next
  builder.AppendLine("</tr>")
Next
builder.AppendLine("</table>")
builder.AppendLine("</body>")
builder.AppendLine("</html>")
WebBrowser1.DocumentText = builder.ToString()

Psal jsem to z hlavy, možná jsem tam nasekal nějaké chyby, ale myšlenka by měla být jasná.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Tady přikládám ještě odkaz na Leteckou poštu, kde je to implementované tím spojováním řetězců, kdyby jste si s tím nevěděl rady. Nechal jsem tam zakomentované vytváření HTML pomocí XDocumentu (to je to XML přímo v kódu, interně se tím zápisem instancují třídy XDocument, resp. XElement, které se dají používat normálně jako každá jiná třída, ale taky tímto speciálním zápisem), aby bylo vidět, jaký je v tom rozdíl, když se použije LINQ a když se použije normální StringBuilder.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Zapomněl jsem na odkaz:

http://leteckaposta.cz/619412402

nahlásit spamnahlásit spam 0 odpovědětodpovědět

XML se ale pomoci StringBuilderu přeci nevytváří! To že C# neumí zápis XML přímo jako literal nebo to tak nejde zapsat ve VS2008 není žádný důvod. LINQ (resp. v tomto případě XLINQ) ve VS2008 už byl a není žádný problém ho použít (v C# I VB.NET). Standardně se XML dokument v C# vytváří například takto (z jednoho reálného projektu):

private static XElement ExportSmena(Smena smena)
{
    return new XElement("Smena",
            new XAttribute("IDSmeny_Vychozi", smena.IDSmeny_Vychozi),
            new XAttribute("Nazev", smena.Nazev),
            new XAttribute("OznaceniSmeny", smena.OznaceniSmeny),
            new XAttribute("TypSmeny", (int)smena.TypSmeny),
            !smena.Nocni ? null : new XAttribute("Nocni", true),
            smena.Poznamka == null ? null : new XAttribute("Poznamka", smena.Poznamka),
            from smenaCasy in smena.Casy
            select new XElement("SmenaCasy",
                    new XAttribute("DenVTydnu", smenaCasy.DenVTydnu),
                    new XAttribute("PracovniDobaOd", smenaCasy.PracovniDobaOd.TimeOfDay),
                    new XAttribute("PracovniDobaDo", smenaCasy.PracovniDobaDo.TimeOfDay),
                    smenaCasy.VnitrniRamecOd == null ? null : new XAttribute("VnitrniRamecOd", smenaCasy.VnitrniRamecOd.Value.TimeOfDay),
                    smenaCasy.VnitrniRamecDo == null ? null : new XAttribute("VnitrniRamecDo", smenaCasy.VnitrniRamecDo.Value.TimeOfDay),
                    smenaCasy.VnejsiRamecOd == null ? null : new XAttribute("VnejsiRamecOd", smenaCasy.VnejsiRamecOd.Value.TimeOfDay),
                    smenaCasy.VnejsiRamecDo == null ? null : new XAttribute("VnejsiRamecDo", smenaCasy.VnejsiRamecDo.Value.TimeOfDay),
                    !smenaCasy.AutomatickePrestavky ? null : new XAttribute("AutomatickePrestavky", true),
                    new XAttribute("FondSmeny", smenaCasy.FondSmeny),
                    from prestavka in smenaCasy.Prestavky
                    select new XElement("Prestavka",
                                new XAttribute("IntervalOd", prestavka.IntervalOd.TimeOfDay),
                                new XAttribute("IntervalDo", prestavka.IntervalDo.TimeOfDay),
                                new XAttribute("Delka", prestavka.Delka))));
}

A zpracovává takto:

private static Smena ParseSmena(string data)
{
    var smena = XElement.Parse(data);

    return new Smena(
        (int)smena.Attribute("IDSmeny_Vychozi"),
        (string)smena.Attribute("Nazev"),
        (string)smena.Attribute("OznaceniSmeny"),
        (TypSmeny)(int)smena.Attribute("TypSmeny"),
        ((bool?)smena.Attribute("Nocni")).GetValueOrDefault(),
        (string)smena.Attribute("Poznamka"),
        (from smenaCasy in smena.Elements("SmenaCasy")
         select new SmenaCasy(
                 (int)smenaCasy.Attribute("DenVTydnu"),
                 DateTime.MinValue.Add((TimeSpan)smenaCasy.Attribute("PracovniDobaOd")),
                 DateTime.MinValue.Add((TimeSpan)smenaCasy.Attribute("PracovniDobaDo")),
                 smenaCasy.Attribute("VnitrniRamecOd") == null ? (DateTime?)null : DateTime.MinValue.Add((TimeSpan)smenaCasy.Attribute("VnitrniRamecOd")),
                 smenaCasy.Attribute("VnitrniRamecDo") == null ? (DateTime?)null : DateTime.MinValue.Add((TimeSpan)smenaCasy.Attribute("VnitrniRamecDo")),
                 smenaCasy.Attribute("VnejsiRamecOd") == null ? (DateTime?)null : DateTime.MinValue.Add((TimeSpan)smenaCasy.Attribute("VnejsiRamecOd")),
                 smenaCasy.Attribute("VnejsiRamecDo") == null ? (DateTime?)null : DateTime.MinValue.Add((TimeSpan)smenaCasy.Attribute("VnejsiRamecDo")),
                 ((bool?)smenaCasy.Attribute("AutomatickePrestavky")).GetValueOrDefault(),
                 (int)smenaCasy.Attribute("FondSmeny"),
                 (from prestavka in smenaCasy.Elements("Prestavka")
                  select new SmenaCasyPrestavka(
                          new DateTime(1900, 1, 1).Add((TimeSpan)prestavka.Attribute("IntervalOd")),
                          new DateTime(1900, 1, 1).Add((TimeSpan)prestavka.Attribute("IntervalDo")),
                          (int)prestavka.Attribute("Delka"))).ToList())
        ).ToList());
}

Ve VB.NET nedělám, ale jde to (až na syntaxi) naprosto stejně.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Pokud bychom mluvili o produkci C# produktu, tak bych se vydal také touto cestou a tazatel by o ní měl vědět, v tom souhlasím.

Přesto si ale nemyslím, že jsem nějak extr hřešil použitím StringBuilderu. To HTML, které generuji, sypu do WebBrowseru, který tam je jen za účelem tisku a to samo o sobě je jakýsi hack, abych tazateli poskytl snadné řešení. Stejně tak jsem tedy šel cestou nejjednoduššího, ale funkčního řešení při generování HTML.

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.
  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:  
Heslo:  

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback