Działanie w tle (WPF, C#)

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.

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

0

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

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 ;)

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:

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.

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.

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ł)

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:

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.

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

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