Czekanie na metodę przy zamykaniu okna

Czekanie na metodę przy zamykaniu okna
ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
0

Witam. Mam problem z zapisem danych, po kliknięciu "X" w programie. Mój kod, w skrócie wygląda tak:

Kopiuj
 private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Save();
}
private async void Save()
{
//działania na wątku okna
//Tutaj funkcje  await Task.Run(() => metoda()));
}

Niestety, wątek okna nie czeka na wykonanie się kodu z "await"... Nie mam pojęcia czemu. Jak ustawie:

Kopiuj
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Close = true;
Save();
}

Wszystko działa jak należy. Poza tym, że oko się nie zamknie...

Wie ktoś może jak rozwiązać ten problem ?
Proszę o pomoc.
Pozdrawiam.

edytowany 2x, ostatnio: Zdziwiony
A6
  • Rejestracja:około 9 lat
  • Ostatnio:ponad 6 lat
  • Postów:20
0
Kopiuj
         protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            if (MessageBox.Show("Czy na pewno chcesz zakończyć ?",
              "Zamknac?", MessageBoxButton.YesNo, MessageBoxImage.Question)
                      == MessageBoxResult.No)
                e.Cancel = true;
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
//****************************
            //tu zapisujsz
        }



ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
0

Sorki, pomyłka ;)

edytowany 1x, ostatnio: Zdziwiony
ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
0

Zrobiłem tak jak radziłeś:

Kopiuj
   protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
        {
            base.OnClosing(e);
            if ((Password_listView.Items.Count > 0) && (IsSave == false))
            {
                if (MessageBox.Show("Czy chcesz zapisać zmiany ?", "Zapis", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
                {
                    e.Cancel = true;
                }
            }
        }
        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);
            Save();
        }

Dostaję takie błędy:
Ważność Kod Opis Projekt Plik Wiersz
Błąd No overload for 'OnClosing' matches delegate 'CancelEventHandler',
oraz
Ważność Kod Opis Projekt Plik Wiersz
Błąd CS0123 Żadne z przeciążeń dla elementu „OnClosing” nie pasuje do delegata „CancelEventHandler”.

PS: Piszę w WPF, może ten kod jest dla WinForms ?

edytowany 1x, ostatnio: Zdziwiony
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Tak zrób:

Kopiuj
        public MainWindow() {
            InitializeComponent();

            var task = new Task(new Action(() => {
                var upperLimit = 1000000000;
                for (int i = 0; i < upperLimit; ++i) { }
            }));
            task.Start();


            this.Window.Closing += (sender, e) => {
                var result = MessageBox.Show("Czy chcesz zamknąć okno?", "", MessageBoxButton.YesNo, MessageBoxImage.Question);
                switch (result) {
                    case MessageBoxResult.Yes:
                        {
                            if (!task.IsCompleted) {
                                MessageBox.Show("Zadanie nie zostało zakończone.");
                                e.Cancel = true;
                            }
                            break;
                        }
                    case MessageBoxResult.No:
                        {
                            e.Cancel = true;
                            break;
                        }
                }
            };
        }

A jeśli chcesz wykonać jakieś zmiany w GUI użyj Dispatcher'a. Ustaw sobie duży upperLimit żebyś zdążył zobaczyć, że okno się nie zamknie dopóki trwa zadanie.

edytowany 3x, ostatnio: grzesiek51114
ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
0

@grzesiek51114, czemu mam wywołać funkcję Save(), w konstruktorze ?
Ja potrzebuję ją wykonać dopiero przy zamykaniu okna.

Kopiuj
private void Save()
{
//coś tam z oknem
await Task.Run(() => metoda()));
await Task.Run(() => metoda()));
//koniec
}
edytowany 1x, ostatnio: Zdziwiony
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

No przecież to co napisałem to jest tylko przykład, żebyś sobie po swojemu rozpisał. Zrób całego sejwa jako task'a i sprawdzaj przy zamknięciu czy zakończył działanie. Jak nie to po prostu nie zamykaj okna.

edytowany 1x, ostatnio: grzesiek51114
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

A dobra... wiem o co Ci chodzi. :D Nie zajarzyłem na początku. Żeby nie zapętlił Ci się event zamykania okna musisz sprawdzać status obiektu task.
Tak będzie dobrze:

Kopiuj
        public MainWindow() {
            InitializeComponent();

            var task = new Task(new Action(() => {
                for (int i = 0; i < int.MaxValue; ++i) { }
            }));

            this.Window.Closing += (sender, e) => {
                if (task.Status != TaskStatus.Running && task.IsCompleted != true) task.Start();
                var result = MessageBox.Show("Czy chcesz zamknąć okno?", "", MessageBoxButton.YesNo, MessageBoxImage.Question);
                switch (result) {
                    case MessageBoxResult.Yes:
                        {
                            if (!task.IsCompleted) {
                                MessageBox.Show("Zadanie nie zostało zakończone.");
                                e.Cancel = true;
                            }
                            break;
                        }
                    case MessageBoxResult.No:
                        {
                            e.Cancel = true;
                            break;
                        }
                }
            };
        }
edytowany 2x, ostatnio: grzesiek51114
ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
0

Nie działa :/

Sam sprawdź, uruchom tym taką metodę:

Kopiuj
  private void Save()
        {
            MessageBox.Show("a");
        }

Zapętla się...

grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
1

Przecież działa i nic się nie zapętla, bo nie może!

Kopiuj
        public MainWindow() {
            InitializeComponent();

            var task = new Task(this.Save);

            this.Window.Closing += (sender, e) => {

                // TO jest kluczowa linijka:
                if (task.Status != TaskStatus.Running && task.IsCompleted != true) task.Start();

                var result = MessageBox.Show("Czy chcesz zamknąć okno?", "", MessageBoxButton.YesNo, MessageBoxImage.Question);
                switch (result) {
                    case MessageBoxResult.Yes:
                        {
                            if (!task.IsCompleted) {
                                MessageBox.Show("Zadanie nie zostało zakończone.");
                                e.Cancel = true;
                            }
                            break;
                        }
                    case MessageBoxResult.No:
                        {
                            e.Cancel = true;
                            break;
                        }
                }
            };
        }

        private void Save() {
            MessageBox.Show("a");
        }

EDIT: Póki nie zamkniesz messagebox'a z literą program nie pozwoli Ci zamknąć okna.

edytowany 3x, ostatnio: grzesiek51114
ZD
Zapętlało się, bo wcześniej było "var task = new Task(new Action(() => { for (int i = 0; i < int.MaxValue; ++i) { } }));" :PP
grzesiek51114
grzesiek51114
@Zdziwiony bo znowu na pałę dopisałeś warunek :P
Patryk27
Moderator
  • Rejestracja:ponad 17 lat
  • Ostatnio:ponad rok
  • Lokalizacja:Wrocław
  • Postów:13042
0

Em, po prostu dodaj sobie flagę IsTaskDone do jakiejś klasy - podczas uruchamia taska ustawiaj tę flagę na false i przy zamykaniu okna czekaj, aż zmieni się na true...


grzesiek51114
grzesiek51114
Nie musi: Task ma w sobie enum'a ze statusem, a jedną z opcji jest TaskStatus.Running. Tylko musi ją najpierw sprawdzić żeby przy każdym naciśnięciu przycisku nie uruchamiał nowego taska. Zresztą ta klasa i tak nie pozwoli mu tego zrobić.
grzesiek51114
grzesiek51114
@Patryk27 widzę, że komentarz mi się skończył. Wszystko zależy do tego co będzie odpalał w takim tasku. Jak to będzie jakaś długa pętla to trzeba koniecznie sprawdzić Running, a dla samego MB wystarczy IsCompleted, bo po prostu przy wciśnięciu przycisku OK wątek się zakończy. :)
ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
1

Ten kod działa:

Kopiuj
this.Closing += (sender, e) => {
                if (task.Status != TaskStatus.Running && task.IsCompleted != true) task.Start();
                var result = MessageBox.Show("Czy chcesz zamknąć okno?", "", MessageBoxButton.YesNo, MessageBoxImage.Question);
                switch (result)
                {
                    case MessageBoxResult.Yes:
                        {
                            if (!task.IsCompleted)
                            {
                                MessageBox.Show("Zadanie nie zostało zakończone.");
                                e.Cancel = true;
                            }
                            break;
                        }
                    case MessageBoxResult.No:
                        {
                            e.Cancel = true;
                            break;
                        }
                }
            };

Potrzebuję jeszcze ustawić wątek na STA... Jak to zrobić, bo raczej "thread.SetApartmentState(ApartmentState.STA);" nie zda tu egzaminu ;P

grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
1

Potrzebuję jeszcze ustawić wątek na STA...

Kopiuj
        private void Save() {
            // Tutaj działania na danych.
            App.Current.Dispatcher.BeginInvoke(new Action(() => {
                // Tutaj działania na GUI.
            }));
        }
ZD
Mam jedną metodę do zapisu, wywołuję ją z menu (czyli bez zamykania okna) i tą samą chcę wywoływać przy zamykaniu okna. Tak, więc teraz moje pytanie: Mogę użyć Dispatchera w tej metodzie i wywoływać ją z pod menu i przy zamykania okna, czy muszę zrobić osobną metodę do zapisu z Dispatcherem do zamykania okna ?
grzesiek51114
grzesiek51114
Mogę użyć Dispatchera w tej metodzie i wywoływać ją z pod menu i przy zamykania okna? Tak
ZD
Czyli jeżeli wywołuję metodę z pod tego samego wątku co okno to Dispatcher będzie ignorowany ?
grzesiek51114
grzesiek51114
Wykona się po prostu :)
grzesiek51114
grzesiek51114
A jak zrobisz BeginInvoke to wykona się asynchronicznie i już.
ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
0

Aha, i jeszcze jedno pytanie
Czym różni się Dispatcher.Invoke, od App.Current.Dispatcher.BeginInvoke, bo zawsze używałem tego pierwszego ?

edytowany 1x, ostatnio: Zdziwiony
grzesiek51114
grzesiek51114
BeginInvoke jest metodą asynchroniczną tzn. służy do asynchronicznego wykonywania kodu. Więcej tutaj: http://stackoverflow.com/questions/19009174/dispatcher-invoke-vs-begininvoke-confusion
ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
0

Ehh, dalej nie do końca działa to tak jakbym chciał

Kopiuj
var task = new Task(Save);
            
            this.Closing += (sender, e) => {
                if (IsSave == false)
                {
                    var result = MessageBox.Show("Czy chcesz zapisać dane?", "", MessageBoxButton.YesNo, MessageBoxImage.Question);
                    if (result == MessageBoxResult.Yes)
                    {
                        if (task.Status != TaskStatus.Running && task.IsCompleted != true) task.Start();
                    }
                    if (!task.IsCompleted)
                    {
                        MessageBox.Show("Zadanie nie zostało zakończone.");
                        e.Cancel = true;
                    }
                    else
                    {
                        e.Cancel = false;
                    }
                }
            };

Muszę jakoś wywoływać zdarzenie Close(), żeby po zakończeniu zadania okno się zamykało.

edytowany 1x, ostatnio: Zdziwiony
0
Kopiuj
 private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
Task.WaitAll(Save());
}
private async Task Save()
{
//działania na wątku okna
    await Task.Run(() => metoda()).ConfigureAwait(false);
}
ZD
Zamraża mi cały wątek główny.
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Zrób własną wersję klasy Task, która będzie miała zdarzenie TaskFinished. Będziesz mógł podpiąć pod nie jakąkolwiek akcję chcesz zamiast dopinać zamykanie na sztywno.

Kopiuj

// Nie zwracaj uwagi na usingi. Poustawiałem sobie uniwersalne :)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace _4programmersWPF {

    public class MyTask : Task {
        public delegate void TaskFinishedEventHandler();
        public TaskFinishedEventHandler TaskFinished;

        public MyTask(Action action) : base(action) { }
        public void FireTaskFinished() {
            if (this.TaskFinished != null) this.TaskFinished();             
        }
    }

    public partial class MainWindow : Window {
        private MyTask task;

        public MainWindow() {
            InitializeComponent();

            this.task = new MyTask(this.Save);
            this.task.TaskFinished += () => {
                App.Current.Dispatcher.BeginInvoke(new Action(() => {

                    //  Należy desubskrybować zdarzenie zamykania okna, bo inaczej
                    //  program nas zapyta czy chcemy je zamknąć.
                    this.Window.Closing -= this.Window_Closing;
                    this.Close();
                }));
            };

            this.Window.Closing += Window_Closing;
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
            if (task.Status != TaskStatus.Running && task.IsCompleted != true) task.Start();
            var result = MessageBox.Show("Czy chcesz zamknąć okno?", "", MessageBoxButton.YesNo, MessageBoxImage.Question);
            switch (result) {
                case MessageBoxResult.Yes:
                    {
                        if (!task.IsCompleted) {
                            MessageBox.Show("Zadanie nie zostało zakończone.");
                            e.Cancel = true;
                        }
                        break;
                    }
                case MessageBoxResult.No:
                    {
                        e.Cancel = true;
                        break;
                    }
            }
        }

        //  Tak, posłużę się tą pętlą, bo na messageboksie nie zauważysz dobrze efektu.
        //  W swoim kodzie zrobisz po swojemu.
        private void Save() {
            for (int i = 0; i < int.MaxValue; ++i) { }
            this.task.FireTaskFinished();
        }
    }
}
edytowany 3x, ostatnio: grzesiek51114
1
grzesiek51114 napisał(a):

Zrób własną wersję klasy Task, która będzie miała zdarzenie TaskFinished. Będziesz mógł podpiąć pod nie jakąkolwiek akcję chcesz zamiast dopinać zamykanie na sztywno.

przecież taski już mają "ContinueWith" które robi to samo

grzesiek51114
grzesiek51114
Masz rzecz jasna rację. Przeoczyłem :)
0

Zamraża mi cały wątek główny

bo nie powiedziałeś że nie ma zamrażać
ogólnie czemu po prostu nie zrobisz zapisu w tle synchronicznie po zamknięciu okna na zdarzeniu "Closed"?

ZD
Bo potrzebuję odczytać dane z tego okna, więc musi być podczas zapisu "istnieć"
0

Coś takiego w sumie wystarczyłoby mi:

Kopiuj
public MainWindow()
        {
            InitializeComponent();
            var task = new Task(Save);
            this.Closing += (sender, e) =>
            {
                
                if (IsSave == false)
                {
                    var result = MessageBox.Show("Czy chcesz zapisać dane?", "", MessageBoxButton.YesNo, MessageBoxImage.Question);
                    if (result == MessageBoxResult.Yes)
                    {
                        if (task.Status != TaskStatus.Running && task.IsCompleted != true) task.Start();
                        IsSave = true;
                        e.Cancel = true;
                    }
                }
                else
                {
                    if (task.Status == TaskStatus.Running == true)
                    {
                        e.Cancel = true;
                    }
                    else
                    {
                        Environment.Exit(0);
                    }
                }
            };
         }

Ale nie mam pojęcia, dlaczego task.Status zawsze zwraca mi true....

ZD
Mój post, byłem wylogowany ;p
grzesiek51114
grzesiek51114
@Zdziwiony a cio to? task.Status == TaskStatus.Running == true porównujesz enuma z boolem?
ZD
Kombinuje już na wszystkie strony... task.IsCompleted zwraca mi zawsze false za to...
ZD
Pomyłka, też true
grzesiek51114
grzesiek51114
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 4 lata
  • Postów:2442
0

Czy wiesz co ta linijka robi: if (task.Status != TaskStatus.Running && task.IsCompleted != true) task.Start();?
Ona dba o to żeby program nie próbował odpalić zadania drugi raz. Dba także o to, żebyś nie odpalił już zakończonego taska.

A to if (IsSave == false) jest Ci kompletnie niepotrzebne! Tylko komplikujesz sobie życie. Dlaczego nie możesz zrobić tego tak jak Ci powiedziałem albo tak jak napisał @mały Młot? Nasze rozwiązania działają i niepotrzebnie bawisz się w komplikowanie sobie życia :)

edytowany 2x, ostatnio: grzesiek51114
ZD
IsSave, używam tylko do tego, żeby nie wyświetlać okienka, w przypadku gdy już zapisze się zmiany z poziomu programu(menu)
grzesiek51114
grzesiek51114
To: if (task.Status == TaskStatus.Running == true) to już w ogóle miazga! Nie rób takich rzeczy.
ZD
Ehh... Nie popatrzałem na typ :P
ZD
  • Rejestracja:ponad 9 lat
  • Ostatnio:ponad 7 lat
  • Postów:99
0

Zdenerwowałem się, że mi nie wychodzi i zrobiłem tak:
Save, uruchamiam z argumentem typu bool, dorzuciłem w tej metodzie dwie linijki:

Kopiuj
if (Exit == true)
this.Close();

I po problemie :D

Dzięki za pomoc :)

edytowany 3x, ostatnio: Zdziwiony
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)