Działanie w tle (WPF, C#)

Działanie w tle (WPF, C#)
shuz
  • Rejestracja:około 3 lata
  • Ostatnio:około 2 lata
  • Postów:1
0

Cześć, podjąłem się amatorskiego wykonania aplikacji do wypełniania protokołów, które trafiają do Word'a. Chciałem aby program na bieżąco przeładowywał zawartość utworzonego dokumentu tzn. pobierał tekst z TextBox'ów i wpisywał go w odpowiednie miejsca. Czy jest to w ogóle możliwe? Próbowałem poprzez stworzenie dodatkowego okienka, w którym w nieskończonej pętli byłyby podmieniane zawartości stringów ale po kompilacji nawet nie pojawia się okienko główne tylko od razu działa pętla w tym drugim.

Barstok
  • Rejestracja:ponad 4 lata
  • Ostatnio:18 dni
  • Postów:9
0

Jak nieskończona pętla to raczej przyda ci się oddzielny wątek do tego, czy tam Taski chyba są w c#. Nowe okienko ci nic nie da

shuz
Czytałem trochę o wątkach ale wydaje mi się, że byłby to trochę przerost formy nad treścią. Nie musi być to koniecznie nieskończona pętla tylko taki wpadł mi pomysł, może być np metoda, która się wywołuje cyklicznie co kilka sekund ale ona też chyba musiałaby być niezależna od okienka głównego
heyyou
  • Rejestracja:ponad 6 lat
  • Ostatnio:5 dni
  • Postów:182
0

jak chcesz, aby mozna bylo jednoczesnie korzystać z aplikacji no musisz to zrobić w innym wątku i tyle ;)
w uproszczeniu

Kopiuj
new System.Threading.Tasks.Task(() =>
{
    while (twój_warunek)
    {
        ZapiszKontrolkeDoWorda();
        System.Threading.Thread.Sleep(1000); // milisekund
    }
}).Start();

tylko tam sobie musisz doczytać o cancellationToken, itd - tj. musisz przy zamykaniu aplikacji (albo w jakimś innym wybranym przez ciebie momencie) ubić tego taskulca ;)

edytowany 3x, ostatnio: heyyou
Zobacz pozostałe 4 komentarze
JU
Chodzi o to, że powinien dać Task.Delay, zamiast Thread.Sleep. Wtedy będzie elegancko. Ten kod może wykonać na wątku głównym. Jeśli będzie await Task.Delay - zdecydowanie wykona się na innym.
SO
No z Task.Delay niewątpliwie byłoby lepiej, ale wciąż nie widzę co tutaj może się wykonać na głównym wątku.
JU
Cały Task może wykonać się na głównym wątku - razem ze Sleepem.
SO
No nie może, bo Taski wykonywane są na ThreadPoolu, a tam nie ma głównego wątku, tak jak pisał @obscurity.
JU
Sprawdziłem i masz rację. Może coś się zmieniło, bo jestem na 100% pewien, że kiedyś na stronach Microsoftu czytałem, że Task może, ale nie musi wykonać się na innym wątku.
JU
  • Rejestracja:około 22 lata
  • Ostatnio:około miesiąc
  • Postów:5042
0

Są jeszcze inne opcje. Np. BackgroundWorker. Czy tam BackgroundTask. Można też zrobić asynchronicznego cyklicznego Taska. Kod będzie podobny do tego pokazanego przez @heyyou tyle że zamiast Thread.Sleep, daj Task.Delay. I użyj async/await w tym miejscu:

Kopiuj
new Task(async () => 
{
  while(...)
  {
    DoJob();
    await Task.Delay(1000);
  }
}

Oczywiście, jeśli DoJob robi coś na kontrolkach, to musisz to odpowiednio synchronizować, bo nie możesz odwołać się do kontrolki z innego wątku niż główny.

CF
  • Rejestracja:ponad 4 lata
  • Ostatnio:około 2 lata
  • Postów:27
1

@shuz: jeżeli zrobisz to aktywną pętlą w osobnym wątku, to program będzie generował dokument nawet jeżeli nie ma żadnych zmian. To będzie upierdliwe jak ktoś będzie chciał otworzyć dokument, zmienić nazwę albo przenieść.

Możesz pokusić się o coś bardziej zwinnego np.:

Gdy textbox rzuca TextChanged, wtedy uruchamiasz 3 sekundowy licznik.
a) jeżeli pojawiło się nowe zdarzenie TextChanged (globalnie dla wszystkich TextBoxów, które powodują nadpisanie dokumentu) restartujesz licznik
b) jeżeli minęły 3 sekundy, ustawiasz wspólną flagę na true.

Pozwala to uniknąć przegenerowania pliku, jeżeli ktoś wciąż coś pisze.

W wątku obok cały czas monitorujesz flagę w pętli i jeżeli jest ona ustawiona na true to zmieniasz ją na false i generujesz dokument. Jeżeli flaga jest ustawiona na false robisz jakieś sleep na sekundę.

Aby robić to jeszcze bardziej zwinne możesz poczytać o wybudzaniu wątku gdy następuje zdarzenie, wtedy w ogóle pozbywasz się aktywnego czekania.

G1
  • Rejestracja:około 4 lata
  • Ostatnio:4 dni
  • Postów:506
0

Może trochę przerost formy nad treścią, pisane na szybko ale u mnie sprawdzało się coś na wzór tego (kolega wyżej to ładnie opisał)

Kopiuj
public class PdfGenerator<Args, Return>
    {
        public delegate Return GeneratePdfDelegate(Args args);

        public PdfGenerator(TimeSpan delay, GeneratePdfDelegate generatePdfMethod)
        {
            Delay = delay;
            this.generatePdfMethod = generatePdfMethod;

            timer = new Timer();
            timer.AutoReset = false;
            timer.Interval = Delay.TotalMilliseconds;
            timer.Elapsed += Timer_Elapsed;
        }

        public TimeSpan Delay { get; private set; }
        private GeneratePdfDelegate generatePdfMethod;

        private Timer timer;
        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            RequestgeneratePdf?.Invoke(this, EventArgs.Empty);
        }
        public event EventHandler<EventArgs> RequestgeneratePdf;
        public event EventHandler<Return> PdfGenerated;

        public void TextChange()
        {
            timer.Stop();
            timer.Start();
        }

        public async void GeneratePdf(Args args)
        {
            await Task.Run(() =>
            {
                Return myPdf = generatePdfMethod(args);
                PdfGenerated?.Invoke(this, myPdf);
            });
        }
        
    }

I przykład użycia bardzo prosty:

Kopiuj
public class Main
    {
        public Main()
        {
            pdfGenerator = new PdfGenerator<string, string>(new TimeSpan(0, 0, 3), (string args) => {
                return $"My Pdf with text {args}";
            });
            pdfGenerator.RequestgeneratePdf += PdfGenerator_RequestgeneratePdf;
            pdfGenerator.PdfGenerated += PdfGenerator_PdfGenerated;
        }

        PdfGenerator<string, string> pdfGenerator;
        private void TextChange(object sender, EventArgs eventArgs)
        {
            pdfGenerator.TextChange();
        }
        private void PdfGenerator_RequestgeneratePdf(object sender, EventArgs e)
        {
            pdfGenerator.GeneratePdf(MyTextBox.text);
        }
        private void PdfGenerator_PdfGenerated(object sender, string e)
        {
            string MyPdf = e;
        }
    }

Pdf będzie się generował po upłynięciu delay czasu bezczynności.

edytowany 1x, ostatnio: gswidwa1
MA
  • Rejestracja:ponad 5 lat
  • Ostatnio:7 dni
  • Postów:20
0

Jeżeli nie musisz targetowac innych platform niż Windows, to DispatcherTimer jest prosty i miły w użyciu oraz idealnie pasuje do wymagań.

https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatchertimer?view=windowsdesktop-6.0

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)