IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
jt.e
Člen
Avatar
jt.e:29.1.2016 21:21

Ahoj, potřeboval bych zase poradit: mám Formulářovou aplikaci, která načítá soubory (do několika Listů, ComboBoxů, TextBoxů apd. Při načítání zobrazuji okno "čekejte prosím..", no a na tomto okně bych rád měl tlačítko "storno", kterým bych chtěl přerušit načítání. Jak na to? (Napadá mne Thread, ale nevím jak s přístupem k formuláři.)

Editováno 29.1.2016 21:23
 
Odpovědět
29.1.2016 21:21
Avatar
Tomáš Brůna
Tvůrce
Avatar
Odpovídá na jt.e
Tomáš Brůna:29.1.2016 21:27

Jaké soubory načítáš? A co používáš na čtení za třídu? :)

Nahoru Odpovědět
29.1.2016 21:27
Vi veri universum vivus vici
Avatar
Tomáš Brůna
Tvůrce
Avatar
Tomáš Brůna:29.1.2016 21:31

jedna z možností by mohla být takto:

private boolean tlacitkoStornoStisknuto;

.....tlacitko_click.......(){
 this.tlacitkoStornoStisknuto = true;
}

....nacti.....
{
 while(this.tlacitkoStornoStisknuto != true)
 {
  //čtení
 }
}
Nahoru Odpovědět
29.1.2016 21:31
Vi veri universum vivus vici
Avatar
jt.e
Člen
Avatar
Odpovídá na Tomáš Brůna
jt.e:29.1.2016 21:37

ani mi tak nejde o vlastní čtení souborů, to trvá asi tak 2-3 sec, ale o ověřování existence souborů a složek - to trvá někdy dost dlouho, protože jsou často v síti.

 
Nahoru Odpovědět
29.1.2016 21:37
Avatar
Tomáš Brůna
Tvůrce
Avatar
Odpovídá na jt.e
Tomáš Brůna:29.1.2016 21:40

promiň, nějak teda nechápu dotaz :), mám bohužel takovou blbou vlastnost že většinu věcí chápu jinak než ostatní ;)

Nahoru Odpovědět
29.1.2016 21:40
Vi veri universum vivus vici
Avatar
jt.e
Člen
Avatar
Odpovídá na Tomáš Brůna
jt.e:29.1.2016 21:47

Moje chyba, jsem to dost podrobně nepopsal (nepovažoval jsem to za důležité). Jde mi o to, že někdy vypadne síť, a pak mi aplikace při načítání zamrzne (třeba na 2 minuty), než zjistí, že je soubor nenalezen. Já bych chtěl mít možnost tu aplikaci ukončit, protože jsem už při tom čekání zjistil, že nefunguje síť.

 
Nahoru Odpovědět
29.1.2016 21:47
Avatar
Adam Ježek
Tvůrce
Avatar
Odpovídá na jt.e
Adam Ježek:29.1.2016 21:50

Pokud dobře vím, tak to nebude zrovna nejjednodušší.
Můžeš sem hodit těch pár řádků kódu ve kterejch kontroluješ přítomnost souboru a načítáš ho?

Možná by to šlo zabalit do vlákna a pak na něj zavolat thread.Abort(), jenže to se už moc nedoporučuje a ani nevim jestli ho to chcípne hned nebo počká na ukončení rozdělané věci.

Editováno 29.1.2016 21:50
Nahoru Odpovědět
29.1.2016 21:50
Počkej chvíli, poradím se s křišťálovou koulí.
Avatar
Tomáš Brůna
Tvůrce
Avatar
Odpovídá na jt.e
Tomáš Brůna:29.1.2016 21:50

tak to netuším :(

Editováno 29.1.2016 21:52
Nahoru Odpovědět
29.1.2016 21:50
Vi veri universum vivus vici
Avatar
jt.e
Člen
Avatar
jt.e:29.1.2016 21:55

Přítomnost souboru testuji klasicky přes File.Existsts()

třeba tohle je první věc co načítám:

/// <summary>
/// načte položky ze souboru
/// </summary>
/// <param name="c"></param>
/// <param name="filename"></param>
/// <param name="silent">true=nebude zobrazovat chybové zprávy</param>
public static void LoadComboItems(this ComboBox c, string filename, bool silent)
{
    if (c.Items.Count > 0) c.Items.Clear();

    try
    {
        string[] lines = File.ReadAllLines(filename, Encoding.Default);
        foreach (string s in lines) c.Items.Add(s);
    }
    catch (Exception e)
    {
        if (silent == false)
        {
            string msg = e.Message + "\nChyba pro soubor:\n" + filename;
            MessageBox.Show(msg, "Chyba", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}
Editováno 29.1.2016 21:57
 
Nahoru Odpovědět
29.1.2016 21:55
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na jt.e
Petr Čech:29.1.2016 22:04

Můžeš to dát do async metody, budeš mít statickou vlastnost bool která bude říkat, jestli se má přerušit načítání. Tu vlastnost zkontroluješ vždy před každým File.Exists, když bude true, nějak to načítání dropneš, třeba returnem.
Asi to není nejlepší řešení, ale je nejjednodušší.
Můžeš se podívat sem: https://msdn.microsoft.com/…vs.110).aspx

Editováno 29.1.2016 22:06
Nahoru Odpovědět
29.1.2016 22:04
the cake is a lie
Avatar
jt.e
Člen
Avatar
jt.e:29.1.2016 22:04

Teď mě napadá, že můžu dát do vlákna pouze File.Exists, a to pak kdykoliv ukončit, ale nevím jako moc rozumné je to řešení....

 
Nahoru Odpovědět
29.1.2016 22:04
Avatar
jt.e
Člen
Avatar
Odpovídá na Petr Čech
jt.e:29.1.2016 22:07

ale to zase nemůžu kontrolovat při metodě File.Exists, myslím si, že z nějakého důvodu trvá dlouho pouze první zjištění, (nejspíš, že jde o podobné umístění), pak to jde rychle.

Editováno 29.1.2016 22:09
 
Nahoru Odpovědět
29.1.2016 22:07
Avatar
jt.e
Člen
Avatar
jt.e:29.1.2016 22:12

To bych asi musel vytvořit další vlákno, které bude kontrolovat ten statický bool a ukončovat vlákno s file.exists. Není to moc "krkolomné" řešení?

 
Nahoru Odpovědět
29.1.2016 22:12
Avatar
Petr Čech
Tvůrce
Avatar
Petr Čech:29.1.2016 23:08

Takže tohle jsem vyplodil: tak by se to mělo správně dělat. Jen tam může být malá prodleva mezi kliknutím a zrušením.

private CancellationTokenSource tokenSource;

        private bool? CheckFiles(IEnumerable<string> files, CancellationToken token)
        {
            try
            {
                foreach (var s in files)
                {
                    token.ThrowIfCancellationRequested();
                    Thread.Sleep(400); //kontrola
                }
                return true;
            }
            catch (OperationCanceledException e)
            {
                MessageBox.Show("canceled");
                return null;
            }
        }

        private async void startBtn_click(object sender, EventArgs e)//start
        {
            tokenSource = new CancellationTokenSource();

            List<string> fileList = new List<string>();
            for (int i = 0; i < 20; i++)
            {
                fileList.Add("");
            }

            bool? loaded=await Task.Factory.StartNew(()=>CheckFiles(fileList,tokenSource.Token),tokenSource.Token);
            MessageBox.Show(loaded.ToString());
        }

        private void stopBtn_click(object sender, EventArgs e)
        {
            tokenSource.Cancel();
        }
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
29.1.2016 23:08
the cake is a lie
Avatar
jt.e
Člen
Avatar
jt.e:30.1.2016 14:27

Sice zatím vůbec nechápu co to vlastně dělá, k věcem jako IEnumerable, CancellationToken, async a await jsem se ještě nedostal. Ale je to to co jsem potřeboval. Díky moc.

 
Nahoru Odpovědět
30.1.2016 14:27
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na jt.e
Petr Čech:30.1.2016 15:02

Aha :D na async a await se podívej, jsou to dost užitečné věci, hlavně pro formulářové aplikace. CancellationToken je zkrátka tkaový blackbox, může ti být celkem jedno, jak to funguje uvniř.
IEnumerable si můžeš představit jako list, ale je lepší dávat jako parametr IEnumerable místo Listu, protože potom tam můžeš dát prakticky jakoukoliv kolekci, třeba i pole a ne jen list. IEnumerable je také užitečný jako návratový typ, protože se dá potom použít yield- další užitečná věcička.

Nahoru Odpovědět
30.1.2016 15:02
the cake is a lie
Avatar
jt.e
Člen
Avatar
jt.e:30.1.2016 18:14

Teď jsem si ještě udělal takovou testovací aplikaci. Protože pořád tomu moc nerozumím, tak nevím, co mám špatně:

public partial class Form1 : Form
{
    private CancellationTokenSource tokenSource;

    public Form1()
    {
        InitializeComponent();
    }

    private bool? CheckFile(string filename, CancellationToken token)
    {
        try
        {
            //token.ThrowIfCancellationRequested(); - před fileexists to ingnoruje
            bool exists = File.Exists(filename);

            token.ThrowIfCancellationRequested();
            return exists;
        }
        catch (OperationCanceledException)
        {
            return null;
        }
    }

    private async void btStart_Click(object sender, EventArgs e)
    {
        tokenSource = new CancellationTokenSource();

        bool? result = await Task.Factory.StartNew(() => CheckFile(@"\\192.128.14.2\test.file", tokenSource.Token), tokenSource.Token);

        if (result == null) MessageBox.Show("Přerušeno uživatelem.");
        else
        {
            string msg = (result.Value) ? "Soubor existuje" : "Soubor nenalezen!";
            MessageBox.Show(msg);
        }
    }

    private void btCancel_Click(object sender, EventArgs e)
    {
        if(tokenSource!=null) tokenSource.Cancel();
    }
}

aplikaci lze sice bez problémů ukončit...
Jak bych to měl upravit, abych stiskem tlačítka ukončil metodu CheckFile? Teď se mi to chová tak, že se CheckFile vykonává do konce, ale pak vypíše přerušeno uživatelem.

 
Nahoru Odpovědět
30.1.2016 18:14
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na jt.e
Petr Čech:30.1.2016 18:20

To je přesně očekávané chování, předpokládal jsem kontrolování velkého množství malých souborů.

Nahoru Odpovědět
30.1.2016 18:20
the cake is a lie
Avatar
jt.e
Člen
Avatar
Odpovídá na Petr Čech
jt.e:30.1.2016 18:26

Ono právě nejdéle trvá ověření toho prvního souboru. Ty ostatní pokud jsou ve stejné složce, se ověří pak už rychle.

 
Nahoru Odpovědět
30.1.2016 18:26
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na jt.e
Petr Čech:30.1.2016 18:32

Obávám se, že to nejde File.Exists nejde přerušit v průběhu. Nešlo by to ani kdyby to bylo ve vlastním vlákně.
Nic ale nebrání tomu, abys dělal jakože to už nepracuje, protože ta úloha se stejně přeruší a vrátí null
asi takto:

private async void btStart_Click(object sender, EventArgs e)
{
    tokenSource = new CancellationTokenSource();

    bool? result = await Task.Factory.StartNew(() => CheckFile(@"\\192.128.14.2\test.file", tokenSource.Token), tokenSource.Token);

    if (result == null) return;//zrušeno
    //tady je už jisté, že operace nebyla zrušena

    string msg = (result.Value) ? "Soubor existuje" : "Soubor nenalezen!";
    MessageBox.Show(msg);
}

private void btCancel_Click(object sender, EventArgs e)
{
    tokenSource?.Cancel();
    MessageBox.Show("Přerušeno uživatelem.");
    //prezentační logika po zrušení
}

Zbytek kódu samozřejmě zůstane. Opravdu to nejde lépe, nebylo by to thread-safe. Nešlo by to myslím ani ukončením procesu.

Nahoru Odpovědět
30.1.2016 18:32
the cake is a lie
Avatar
Petr Čech
Tvůrce
Avatar
Petr Čech:30.1.2016 18:49

nebo nebudeš nic předstírat a přiznáš barvu: (asi čistější)

private CancellationTokenSource tokenSource;
private bool wasIoException=false;//došlo k vnitřní chybě?

private bool? CheckFile(List<string> filenames, CancellationToken token)//pokud je těch souborů víc,
//a chceš je kontrolovat najednou, mělo by to vypadat takto:
{
    wasIoException=false;
    try
    {
        foreach(var file in filenames)
        {
            token.ThrowIfCancellationRequested();//kontrolovat to až potom je úplně k ničemu
            if(!File.Exists(file))
                return false;
        }
        return true;
    }
    catch (OperationCanceledException)
    {
        return null;
    }
    catch(IOException)//nepřístupnost souboru
    {
        //tady nemůžeš k UI, musíš to ošetřit až dál
        wasIoException=true;//proto si to zapíšeš
        return null;
    }
}

private async void btStart_Click(object sender, EventArgs e)
{
    tokenSource = new CancellationTokenSource();

    bool? result = await Task.Factory.StartNew(() => CheckFile(@"\\192.128.14.2\test.file", tokenSource.Token), tokenSource.Token);

    if (result == null)
    {
        checking_canceled();
        return;//zrušeno
    }
    //tady je už jisté, že operace nebyla zrušena

    string msg = (result.Value) ? "Soubor existuje" : "Soubor nenalezen!";
    MessageBox.Show(msg);
}

private void btCancel_Click(object sender, EventArgs e)
{
    tokenSource?.Cancel();
    //ukážeš něco jako rušení operace
}

private void checking_canceled()
{
    //tady můžeš pracovat s UI
    //logika, kdy je to už opravdu přerušené
    //vypneš hlášku rušení operace
    if(wasIoException)
    {
        //nastala chyba při kontrolování, ale operace nebyla zrušena
    }
    else
    {
        //operace byla zrušena uživatelem
    }
}
Nahoru Odpovědět
30.1.2016 18:49
the cake is a lie
Avatar
jt.e
Člen
Avatar
Odpovídá na Petr Čech
jt.e:30.1.2016 19:03

Vypadá to nádherně. Díky moc.

 
Nahoru Odpovědět
30.1.2016 19:03
Avatar
Petr Čech
Tvůrce
Avatar
Odpovídá na jt.e
Petr Čech:30.1.2016 19:30

Není zač

Nahoru Odpovědět
30.1.2016 19:30
the cake is a lie
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 23 zpráv z 23.