Wzorzec Repozytorium - jak wyświetlić kategorie w dropdownlistfor?

Wzorzec Repozytorium - jak wyświetlić kategorie w dropdownlistfor?
S7
  • Rejestracja:około 12 lat
  • Ostatnio:ponad 5 lat
  • Postów:287
0

Mam klasy i do nich interfejsy

Kopiuj
[Table("Product")]
    public class Product
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
        public int ProductId { get; set; }

        [Required(ErrorMessage = "Product Name is required.")]
        [DisplayName("Product Name")]
        [MaxLength(50)]
        public string PorductName { get; set; }

        public int CategoryId { get; set; }  

        public virtual Category Category { get; set; }
    }

    public class EFProductRepository : IProductRepository
    {
        private EFContext context = new EFContext();

        public IEnumerable<Product> GetAllProducts
        {
            get { return context.Products; }        
        }       

        public void ProductCreate(Product p)
        {
            context.Products.Add(p);
            context.SaveChanges();
        }
    }

oraz

Kopiuj
[Table("Category")]
    public class Category
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 
        public int CategoryId { get; set; }

        [Required(ErrorMessage = "Category is required.")]
        [DisplayName("Category Description")]
        [MaxLength(50)]
        public string CategoryDescription { get; set; }

        public virtual ICollection<Product> Products { get; set; }
    }

    public class EFCategoryRepository : ICategoryRepository
    {
        private EFContext context = new EFContext();

        public IEnumerable<Category> Categories
        {
            get { return context.Categories; }
        }
    
    }

Controller

Kopiuj
public class ProductController : Controller
    {

        private IProductRepository repository;

        public ProductController(IProductRepository repo)
        {
            repository = repo;        
        }
       
        public ActionResult ProductList()
        {
            ProductListViewModel plvm = new ProductListViewModel
            {
                Products = repository.GetAllProducts                
            };

            return View(plvm);
        }

        [HttpGet]
        public ActionResult ProductCreate()
        {
            return View();        
        }

        [HttpPost]
        public ActionResult ProductCreate(Product product)
        {
            if (ModelState.IsValid)
            {
                TempData["Save"] = "ok";
              //  return View(product);
            }

            return View(product);       
        }
    } 

Widok

Kopiuj
@model WebDev.Models.Product
(...)
@using (Html.BeginForm("ProductCreate", "Product", FormMethod.Post))
        { 
            <p>
                @Html.LabelFor(model => model.PorductName)
                @Html.TextBoxFor(model => model.PorductName)
                @Html.ValidationMessageFor(model => model.PorductName)
            </p>     
            
            <p>
                @Html.LabelFor(model => model.Category.CategoryDescription)
                @Html.DropDownListFor(model => model.CategoryId, new SelectList(@Model.Category, "CategoryId", "CategoryDescription"), "Choose Category", null)
            </p>   
            
            <input type="submit" value="Save" />
        }

Jak zgodnie ze sztuką wzorca projektowego wyświetlić wszystkie kategorie z encji "Categories" w kontrolce widoku DropDownListFor aby potem móc utworzyć w tabeli nowy rekord. Używając wyłącznie modeli widoku, bez ViewBagów itp.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
1

Repozytorium nie ma żadnego związku z GUI, z żadnymi dropdownami, z żadnymi ViewBagami.

Twój problem polega na tym, że próbujesz używać w GUI obiektu reprezentującego strukturę danych w bazie. Sprawy by nie było, gdybyś nie łączył tych dwóch oddzielnych światów i po prostu utworzył klasę ViewModel, który będzie zawierał dane o Produkcie, czyli ProductName oraz CategoryId oraz dodatkowe dane potrzebne do edycji, czyli w Twoim przypadku listę wszystkich kategorii.

PS Dlaczego masz właściwość, która ma w nazwie Get? Przecież jeśli coś jest wyrażeniem z czasownikiem w trybie rozkazującym, to musi być metodą. No i raczej CreateProduct niż ProductCreate. No i raczej ta metoda powinna nazywać się Add, bo ona dodaje produkt do listy, a nie go tworzy.

PPS Tak ogólniej: http://commitandrun.pl/2016/05/11/Repozytorium_najbardziej_niepotrzebny_wzorzec_projektowy/

S7
  • Rejestracja:około 12 lat
  • Ostatnio:ponad 5 lat
  • Postów:287
0

Dzięki @somekind. Tak, chciałem użyć ViewModel np. jak poniżej

Kopiuj
public class ProductViewModel
    {
        public Product Product { get; set; }

        // to (1)
        public IEnumerable<Category> Categories { get; set; }
        // lub (2)
        public IEnumerable<Category> Categories
        {
            get
            {                
                return new EFContext().Categories;            
            }           
        }
    }

tylko, że (2) to łamie tzw. zależności, gdzie zależność klas miedzy sobą nie powinna występować lub występować jak najrzadziej. Innym sposobem, aby pominąć tą zależność klas to zastosowanie (1) i w konstruktorze kontrolera zastosować dwa repozytoria IProduct i ICategory - pytanie czy to zgodne? Czytałem, że tak, że kontroler może zawierać kilka repozytoriów.

Nazewnictwo metod i właściwości trochę małoważna. Ale dzięki za info. Też dziękuję za link, trochę zrozumiałem, trochę nie. Bardziej mi zależy na rozwiązaniu na powyższe.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
1
szymon7500 napisał(a):

Dzięki @somekind. Tak, chciałem użyć ViewModel np. jak poniżej

Kopiuj
public class ProductViewModel
    {
        public Product Product { get; set; }
        // to (1)
        public IEnumerable<Category> Categories { get; set; }
        // lub (2)
        public IEnumerable<Category> Categories
        {
            get
            {                
                return new EFContext().Categories;            
            }           
        }
    }

To nie jest ViewModel, bo:

  1. Jest tam jakiś EFContext, a ViewModel to ma być proste DTO, które tylko przechowuje dane i nie wykonuje żadnych operacji.
  2. ViewModel nie powinien mieć żadnych powiązań z PersistenceModelem (u Ciebie klasy Product, Category). ViewModel może zawierać właściwości typów "prostych" oraz inne ViewModele.

Taka klasa powinna wyglądać tak:

Kopiuj
public class ProductVewModel
    {
        public int ProductId { get; set; }
 
        [Required(ErrorMessage = "Product Name is required.")]
        [DisplayName("Product Name")]
        [MaxLength(50)]
        public string PorductName { get; set; }
 
        public int CategoryId { get; set; }  
 
        public IList<CategoryViewModel> Categories { get; set; }
    }

w konstruktorze kontrolera zastosować dwa repozytoria IProduct i ICategory - pytanie czy to zgodne? Czytałem, że tak, że kontroler może zawierać kilka repozytoriów.

Kontroler nie może zawierać żadnego repozytorium. Repozytorium to logika biznesowa, kontroler to warstwa prezentacji. Wstrzykiwanie repozytoriów do kontrolera, to tak, jakby w samochodzie położyć silnik na siedzeniu pasażera.

Ale Twoje repozytoria to nie są żadne repozytoria, bo nie piszesz aplikacji zgodnie z Domain Driven Design. To po prostu Data Access Object, który nazwałeś repozytorium, bo pewno tak przeczytałeś w tutorialu. (99% tutoriali kłamie.) Te Twoje obiekty to tak naprawdę wrappery na klasy Entity Frameworka. Możesz ich kilka sobie wstrzyknąć do kontrolera, tylko czy one cokolwiek Ci dają? Skoro już chcesz pisać prostą, jednowarstwową aplikację, to nie prościej po prostu wstrzyknąć jeden DbContext?

Nazewnictwo metod i właściwości trochę małoważna.

Wręcz przeciwnie. To jest ważniejsze niż języki i technologie, w których piszesz, niż biblioteki, których używasz, niż wzorce, które stosujesz. Kod pisze się po to, aby inni programiści mogli go przeczytać bez mruczenia pod nosem: "o co tu chodzi?" albo "co za debil to pisał?". Konfundujące nazwy i niechlujstwo czynią kod nieczytelnym.

edytowany 1x, ostatnio: somekind
BU
Przeczytałem artykuły na Twoim blogu i bardzo mi namieszałeś. Od jakiegoś czasu szukam rozwiązania problemu z tymi wszystkimi warstwami, repozytoriami, UoW, serwisami itp i doszedłem do wniosku, że z moją obecną wiedzą wstrzyknięcie DbContext do kontrolera będzie najlepszym wyjściem, bo inaczej nie będę mógł pozbyć się wrażenia, że wszystko zrobiłem źle. Czy w takim przypadku w projekcie należy mieć osobny moduł, który zawiera klasy odwzorowujące tabele i klasę DbContext i czy można go nazywać DAL? Jak będę miał czas na poznanie DDD, to pomyślę nad lepszym rozwiązaniem.
somekind
Nie, to inni mieszają. Ja to tylko próbuję wyprostować. Wstrzykiwanie DbContextu do kontrolera jest uproszczeniem, łamaniem MVC, no ale może mieć sens w prostej aplikacji. Chociaż ja nawet prostą aplikację bym napisał inaczej. Czy w takim przypadku w projekcie należy mieć osobny moduł, który zawiera klasy odwzorowujące tabele i klasę DbContext i czy można go nazywać DAL? - owszem, można tak zrobić.
BU
Namieszałeś niekoniecznie w złym znaczeniu.
S7
  • Rejestracja:około 12 lat
  • Ostatnio:ponad 5 lat
  • Postów:287
0

Dzięki wielkie za odpowiedź.

Przykład wziąłem z książki Adama Freeman-a, z małą przeróbką jeśli chodzi o kategorie. Chciałem, aby kategorie były w bazie, w oddzielnej tabeli i podczas dodawania produktu można byłoby je wybrać za pomocą DropDownList i zapisać jako id w tabeli Product. Zrobiłem podobnie jak było to zrobione z Product-em, ponieważ chciałem zadziałać niejako na wielu repozytoriach. Mam dwa repozytoria, jeden kontroler, jak poniżej

Kopiuj
(...)
        private IProductRepository repository;
        private ICategoryRepository cat;

        public ProductController(IProductRepository repo, ICategoryRepository categories)
        {
            repository = repo;
            cat = categories;
        }
(...)

Coś na wzór: http://sampathloku.blogspot.com/2012/10/how-to-use-viewmodel-with-aspnet-mvc.html

ViewModel skopałem, na szybko robione i chciałem mieć szybki efekt na potrzeby odpowiedzi.

S7
  • Rejestracja:około 12 lat
  • Ostatnio:ponad 5 lat
  • Postów:287
0

Reasumując: czy istnieje możliwość nauczenia się wzorców ze stron internetowych lub z książek? Czy to daremny trud?

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
3

Teorii tak. Tylko trzeba patrzeć na sensowne strony i sensowne książki, a nie jakieś hinduskie blogi, CodeProject czy tutoriale Entity Frameworka, bo to nie jest miejsce na naukę architektury.

http://gorodinski.com/
http://blog.sapiensworks.com/
https://lostechies.com/
http://martinfowler.com

I najważniejsze, nie ograniczać się do jednego miejsca tylko każdą swoją wątpliwość sprawdzać w kilku.

MMSz
  • Rejestracja:ponad 8 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Gdynia
  • Postów:19
0

Podobnie jak twórca tematu jestem początkujący i korzystam z książki Freemana o ASP.NET MVC. Im bardziej się w nią zagłębiam i im więcej czytam o wzorcu repozytorium i MVC tym mniej rozumiem z tego co "autor miał na myśli".

somekind - napisałeś: "Kontroler nie może zawierać żadnego repozytorium. Repozytorium to logika biznesowa, kontroler to warstwa prezentacji. Wstrzykiwanie repozytoriów do kontrolera, to tak, jakby w samochodzie położyć silnik na siedzeniu pasażera."

Bazując na przykładach z książki Freemana również mam wstrzyknięte repozytorium do kontrolera w swoim projekcie. Jeśli jest to uchybienie, to jak powinno wyglądać powiązanie kontrolera z repozytorium, aby za jego pośrednictwem pobierał dane z bazy?

Kopiuj
 private ITicketRepository ticketRepository;

        public TicketController(ITicketRepository ticketRepository)
        {
            this.ticketRepository = ticketRepository;
        }
edytowany 1x, ostatnio: MMSz
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
0
MMSz napisał(a):

Jeśli jest to uchybienie, to jak powinno wyglądać powiązanie kontrolera z repozytorium, aby za jego pośrednictwem pobierał dane z bazy?

Wcale nie powinny być powiązane. Kontroler powinien odwoływać się do jakiegoś serwisu wystawiającego API biznesowe aplikacji, ten serwis ma pod sobą serwisy domenowe, encje, repozytoria i całe to DDD. Zaś sam serwis (z którego kontrole korzysta) może zwracać jakieś DTO albo nawet gotowe ViewModele.

A jak nie chcesz mieć tak skomplikowanego projektu z DDD, to po prostu nie używaj repozytoriów, tylko wstrzyknij sobie kontekst ORMa do kontrolera. Będziesz miał w aplikacji dokładnie tyle samo warstw, co tym biedarepozytorium Freemana.

MMSz
  • Rejestracja:ponad 8 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Gdynia
  • Postów:19
0

Projekt nad którym pracuję ma dla mnie charakter typowo edukacyjny. Myślę, że na moim pułapie wiedzy podejście DDD, które sugerujesz to jeszcze za wysoka półka - w końcu newbie. :) Może się mylę - może brak mi czegoś co nazywam wzorcem wzorca. ;)

Zastanawiam się czy w ogóle początkujący jak ja powinni tak głęboko wnikać w architekturę. Freeman używa "biedarepozytorium" w swoim szkoleniowym przykładzie. Może właśnie zaimplementowanie takiego biedarepozytorium ma być wstępem, który ułatwi w niedalekiej przyszłości stworzenie repozytorium z prawdziwego zdarzenia? Chociaż rozumiem, że doświadczony programista powie, że to nauka złych nawyków.

To, że w ogóle to całe repozytorium jest "jakimś" ogólnie znanym wzorcem projektowym dowiedziałem się chyba dwa tygodnie po zaimplementowaniu pierwszych biedarepozytoriów w swoim projekcie :). Potem przeczytałem dziesiątkę postów i artykułów o tym, że repozytorium jest samo w sobie złe, a jeżeli ktoś stwierdzał, że złe nie jest, to w ślad za tym szła jednak opinia, że w przynajmniej 99% przypadków wzorzec jest niepoprawnie implementowany/rozumiany (m.in. na smutnym blogu o programistycznej rzeczywistości). Ja jestem "wannabe programmer" i pewnie, że chciałbym, żeby architektura mojej aplikacji była cycuś-glancuś, ale ja jeszcze nie łapię co gdzie umieszczać w projekcie MVC... Po kolei.

No właśnie. Załóżmy, że pójdę ścieżką nr 2 i będę wstrzykiwał kontekst ORM-a do kontrolera. Wypada jeden trybik z maszyny - biedarepozytoria. Zabrałem się za EF w podejściu Code First, napisałem odpowiednie klasy, stworzona została struktura bazy danych. Na razie jest anemia w modelu. Wcześniej zdawało mi się, że metody do operowania na obiektach biznesowych mają znajdować się w tych pseudorepozytoriach. Jeśli nie to gdzie? Jak uniknąć logiki biznesowej w kontrolerze? Czy klasy POCO powinny zawierać również metody? Wiem, że z perspektywy programisty ze stażem pytania mogą wydawać się śmieszne, ale mam wrażenie, że tutoriale i książki, z których korzystałem w ogóle nie nauczyły mnie odpowiadać na takie pytania...

edytowany 2x, ostatnio: MMSz
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
2
MMSz napisał(a):

Zastanawiam się czy w ogóle początkujący jak ja powinni tak głęboko wnikać w architekturę. Freeman używa "biedarepozytorium" w swoim szkoleniowym przykładzie. Może właśnie zaimplementowanie takiego biedarepozytorium ma być wstępem, który ułatwi w niedalekiej przyszłości stworzenie repozytorium z prawdziwego zdarzenia?

Rozumiem upraszczanie czegoś dla początkujących, rozumiem upraszczanie na potrzeby prostych aplikacji, nie rozumiem błędnego nazewnictwa uczącego, że ogórek jest arbuzem.

Chociaż rozumiem, że doświadczony programista powie, że to nauka złych nawyków.

Niestety nie - oni też uczyli się z książek i tutoriali powielających błędy, więc sami je powielają.

To, że w ogóle to całe repozytorium jest "jakimś" ogólnie znanym wzorcem projektowym dowiedziałem się chyba dwa tygodnie po zaimplementowaniu pierwszych biedarepozytoriów w swoim projekcie :).

Ja bym raczej powiedział, że ta nazwa jest powszechnie używana, ale sam wzorzec ogólnie nieznany. :)

Wcześniej zdawało mi się, że metody do operowania na obiektach biznesowych mają znajdować się w tych pseudorepozytoriach.

Taki jest właśnie efekt pokazywania początkującym pseudorepozytoriów, które są używane przez kontrolery, zamiast od razu pokazać jakiś sensowny kawałek kodu.

Jeśli nie to gdzie? Jak uniknąć logiki biznesowej w kontrolerze?

Przenieść ją do innej klasy. Np. jakiegoś serwisu, z którego korzysta kontroler (a ten serwis niech operuje na anemicznym modelu i kontekście ORMa). Albo do obiektów (encji) biznesowych - niech np. faktura sama ma metodę dodającą do niej nową pozycję. (Tylko z takich encji też nie powinno korzystać się bezpośrednio w kontrolerach.)

Czy klasy POCO powinny zawierać również metody?

Wtedy już nie będą POCO. :)

Wiem, że z perspektywy programisty ze stażem pytania mogą wydawać się śmieszne, ale mam wrażenie, że tutoriale i książki, z których korzystałem w ogóle nie nauczyły mnie odpowiadać na takie pytania...

E tam, nie ma nic śmiesznego w konkretnych pytaniach na sensowne tematy.

MMSz
  • Rejestracja:ponad 8 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Gdynia
  • Postów:19
0
[somekind napisał(a)]

ViewModel nie powinien mieć żadnych powiązań z PersistenceModelem (u Ciebie klasy Product, Category). ViewModel może zawierać właściwości typów "prostych" oraz inne ViewModele.

Właściwie to dlaczego tak jest? Pomijam już fakt, że w wielu tutorialach i u tego nieszczęsnego Freemana również powiązanie ViewModelu z persistence modelem jest normą. Załóżmy, że potrzebuję uzyskać efekt jak w przykładzie przedstawiownym przez @szymon7500. Chcę wszystkich danych o produkcie i listę kategorii do wyświetlenia w formularzu edycji. Intuicja mówi:

Kopiuj
public class ProductEditViewModel {
public Product Product { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}

Dla mnie byłoby to niesamowite uproszczenie sprawy, a mapowanie odbyło by się chwila moment. Nie twierdzę oczywiście, że tak powinno być. Pytam jedynie, dlaczego tak nie powinno być? W czym tkwi haczyk, czyli o czym jeszcze nie wiem? :)

edytowany 2x, ostatnio: MMSz
BU
  • Rejestracja:około 10 lat
  • Ostatnio:8 dni
  • Postów:422
1

Na moje oko powyższe rozwiązanie wygląda nienaturalnie. Pierwsza właściwość może powodować problemy z filtrami i gdy trzeba będzie dodać dodatkowe właściwości, to będzie brzydko wyglądało, np. w celu edycji użytkownika trzeba podać hasło i potwierdzenie hasła, ale bazę danych interesuje tylko jedno hasło. Druga właściwość według mnie nie powinna wymuszać używania w widoku SelectList, widok powinien sam sobie z tym poradzić. Ja użyłbym IEnumerable<Category>, chociaż domyślam się, że typ kolekcji też powinien być jakimś DTO. Też chętnie usłyszę poprawną odpowiedź.

MMSz
  • Rejestracja:ponad 8 lat
  • Ostatnio:ponad 6 lat
  • Lokalizacja:Gdynia
  • Postów:19
0

Też myślałem o użyciu IEnumerable<Category>.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
0
MMSz napisał(a):

Właściwie to dlaczego tak jest?

Bo klasa powinna mieć tylko jeden powód do zmiany (SRP), a taka uniwersalna klasa, która się zapisuje do bazy danych, wyświetla w interfejsie, parzy kawę i stepuje, ma zdecydowanie więcej powodów do zmian niż powinna.
Druga rzecz to separation of concerns, obiekty z jednej warstwy nie powinny wyciekać do innych warstw. Co za tym idzie, nie trzeba np. referencjonować ORMa w warstwie GUI.

Chcę wszystkich danych o produkcie

Serio? Potrzebujesz jego id, daty ostatniej edycji albo nazwiska pracownika, który go utworzył?

Pytam jedynie, dlaczego tak nie powinno być? W czym tkwi haczyk, czyli o czym jeszcze nie wiem? :)

To napisz kod klasy Product, tak aby:

  1. Zawierał Id, nazwę, opis, numer produktu, kategorię, podkategorię, producenta, cenę, masę oraz wymiary zewnętrzne.
  2. Na widoku listy produktów ma się wyświetlać numer oraz nazwy: produktu, kategorii, podkategorii i producenta
  3. W widoku tworzenia wszystko poza Id ma być edytowalne.
  4. W widoku edycji dla zwykłego pracownika wszystko poza id oraz numerem produktu i ceną ma być edytowalne.
  5. W widoku edycji dla kierownika możliwa ma być także edycja numeru produktu oraz ceny.
  6. W widoku podglądu produktu dla klienta widoczna była cena dostawy. (W normalnym viewmodelu byłaby to po prostu właściwość, obliczona w serwisie na podstawie danych pobranych z API firmy kurierskiej na podstawie wymiarów i masy.)
Burmistrz napisał(a):

Ja użyłbym IEnumerable<Category>, chociaż domyślam się, że typ kolekcji też powinien być jakimś DTO.

Właściwie nie widzę powodu tworzenia specyficznego typu kolekcji w takim przypadku.

BU
  • Rejestracja:około 10 lat
  • Ostatnio:8 dni
  • Postów:422
0

Czy nie warto tworzyć prostych repozytoriów* nawet tylko dla samego ułatwienia pisania testów jednostkowych? Nie podoba mi się mockowanie Entity Framework z tutorialu https://www.asp.net/web-api/overview/testing-and-debugging/mocking-entity-framework-when-unit-testing-aspnet-web-api-2#testcontext. Wydaje m się, że łatwiej by było mockować repozytorium, niż tworzyć taki skomplikowany sztuczny obiekt. Jest na to jakieś łatwiejsze i sensowne rozwiązanie?

*Proste repozytoria, czyli takie, które zawierają metody:

  • Get(lista filtrów, wybór sortowania, podział na strony),
  • GetById(),
  • Insert(),
  • Update(),
  • Delete().
edytowany 4x, ostatnio: Burmistrz
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:około 2 godziny
  • Lokalizacja:Wrocław
0

@Burmistrz, tylko po co to nazywać Repozytorium, a nie np. Dao?

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)