Programování
MVC Views
Navazuju na základy
Při zavolání metody View() se vrátí uživately .cshtml soubor se stejným názevem jako je akce kontroleru. Bude hledat v souborech:
  • \Views\[Jmeno controlleru]\[jmeno Akce].cshtml
  • \Views\Shared\[jmeno Akce].cshtml
Poznámka: Jakýkoliv view, který má být sdílený pro všechny kontrollery, ve složce share, by měl začínat na _

Pokud chceme, aby vrátil jiný view s jiným jménem tak stačí vložit jméno view jako parametr do view. Například ->
    

return View();
/* Vrátí view v
\Views\[Jmeno controlleru]\[jmeno Akce].cshtml
nebo
\Views\Shared\[jmeno Akce].cshtml
*/

return View("Priklad");
/* Vrátí view Priklad.cshtml
\Views\[Jmeno controlleru]\Priklad.cshtml
nebo
\Views\Shared\Priklad.cshtml
*/
    
Každý view obsahuje takzvaný model. Model je podle čeho se bude stánka vytvářet a řídit.
Obvyklou praxí je vytvořit ke každému view nějaký model který bude mít koncovku *page.cs. Příklad:

Potřebujeme vytvořit webovou stánku na ukazování logu
    
public class Log
{
    public string Action { get; set; }

    public string Message { get; set; }

    public DateTime Date { get; set; }
}
    
Těchto logu máme hodně v databázi a potřebujeme ukázat všechny, vezeme si data z databaze a vložíme do view (v kontrolleru)
    
public IActionResult Vypislogu()
{
    List<Log> logy = context.tbLogs.ToList();

    return View(logy);

    /*
    Poznámka:
    Pokud vkládáme do View typ objekt a 
    nikoliv string, bere se to jako model nikoliv jako název .cshtml

    Pokud chceme zobrazit jiný view tak 
    musíme uvést model jako sekundarní parametr
    */

    return View("Vypislogu",logy);
    //Vratí View "Vypislogu.cshtml" s modelem List<Log>
}
    
Tohle je nejlehčí uvedení dat do view (později ukažu view), ale správný postup by byl, že si vytvořit třídu "LogPage.cs", která bude mít v sobě List<Log>.

Je to kvůli tomu, že nyní jsme limitovaný na to co všechno dokáže List udělat. Nemužeme pak předat do view například od kdy do kdy se brali logy.

Dalším důvod muže být taky to, že databázový objekty musí mít bezparametrický konstruktor, avšak page muže mít konstruktor a tudiž specifikujeme co je potřeba na vykreslení stránky.
Jedná se však čístě o Design pattern a může být nahrazený viewbagama (později vysvětleno)
    
public class Log
{
    public string Action { get; set; }

    public string Message { get; set; }

    public DateTime Date { get; set; }
}

public class LogPage
{
    public List<Log> Logs { get; set; }

    public DateTime EndTime { get; set; } 
    // Určujeme do jaký doby jsme sbírali logy

    public LogPage(List<Log> logs, DateTime endTime)
    {
        Logs = logs;
        EndTime = endTime;
    }
}

public IActionResult Vypislogu()
{
    List<Log> logy = context.tbLogs.ToList();

    return View(new LogPage(logy, DateTime.Now()));

}
    
View
Nyní si vytvoříme cshtml(view) na cestě \Views\[Controller]\Vypislogu.cshtml
Tímto vytváříme takzvaný razor page, který nám dovoluje kombinovat .html a c# dohromady.

Pokud napíšeme specialní znak "@" tak nám dovoluje interagovat se c# kódem. Pokud chceme napsat jen zavináč tak musíme napsat dva @@
Po vytvoření view se nám vytvoří prázdný html, která se vloží na pozici @RenderBody(). Tuto metodu mužeme najít v souboru \Views\Shared\_Layout.cshtml a funguje takto: Veškerý .cshtml co napíšeme ve view se propíše přesně tam, kde se nachází @RenderBody();

Hlavička html, css linky a js scripty se budou nacházet vždy v _Layout jelikož se musí zobrazit vždy.

Na začátku .cshtml definujeme @model, aby view vědělo s čím pracujeme. Musíme napsat uplnou cestu. Nebo můžeme přidat using do souboru \Views\_ViewImports.cshtml
    
@model LogPage
    
// Uplna cesta
@model [NazevProjekt].[Slozka kde se nachazi].[třída]

// Příklad
@model MaturitaWeb.Models.PageLog

// Pokud chceme nějakou hodnotu napsat do view
// Používáme model s velkým M
@Model.EndTime.ToShortDateString()

//////////////////////////////////////////////////////////////////////////////////////////////
// Lze kombinovat html a c#, napříkad:

<div>
	Posledni log v datu: @model.EndTime.ToShortTimeString()
<div/>
    
==

Posledni log v datu: 21:09

//////////////////////////////////////////////////////////////////////////////////////////////
// Pokud potřebujeme něco složitějšího, tak stačí dát do závorek

<div>
	Posledni log v datu: @(Model.EndTime.ToShortDateString() + " v evropském čase" )
<div/>
    
==

Posledni log v datu: 21:09 v evropském čase

//////////////////////////////////////////////////////////////////////////////////////////////
// pokud chceme vložit CELY html element tak musímě použít metodu Html.Raw

@Html.Raw("<div>
	Posledni log v datu: @(Model.EndTime.ToShortDateString() + " v evropském čase" )
<div/>")

==

Posledni log v datu: 21:09 v evropském čase

//////////////////////////////////////////////////////////////////////////////////////////////
// Lze používat i komplikovanější metody jako jsou

@foreach
@while
@for
@if
@switch

// Například:

@foreach(var log in Model.Logs)
{
    	<div>
		Akce: @("Sudo " + log.Action)
	<div/>
    	<div>
		Text: @log.Message
	<div/>
}

==
Akce: Sudo Pokus
Text: Pokud o pokus Pokus
Akce: Sudo neco
Text: Proste neco
...


    
Asp tributy
Razor engine nám dovoluje používat specialní atributy (většinou začínají na asp) v html tagách
na vytvoření odkazu nemusíme specifikovat přesnou cestu, ale můžeme používat asp cesty
    

// Tímto se dostaname na controller Home a na akci VypisLogu
<a asp-controller="Home" asp-action="Vypislogu"></a>
    
Partial view
Tímto mužeme vložit .cshtml stánku do .cshtml stránky. Partial view hledá vždy v \Views\Shared\[jmeno].cshtml
    
<partial name="_PartialName" />
Nebo mužeme úvést úplnou cestu
<partial name="~/Pages/Folder/_PartialName.cshtml" />
    
Ovšem nejlepší způsob na volání .cshtml partial je
    
@await Html.PartialAsync("_PartialName")
    
Tohle vytvoři asynchroně (složité), zkráceně je to lepší pro web
Více informací: learn.microsoft.com
ViewComponents
Tímto mužeme vložit .cshtml stánku do .cshtml stránky, ale před vložením se spustí Invoke metoda na serveru. Takže je možné dotáhnout potřebné data a použít jiný Model na vykreslení.

je potřeba vytvořit třídu [jmeno]Component.cs, která bude dědit z viewComponent
    

// LogComponent.cs
public class LogComponent : ViewComponent
{
    // Musí se jmenovat Invoke, jelikož se vždy spouští metoda invoke
    public IViewComponentResult Invoke(Log log)
    {
        //Vracíme view, který se bude nacházat v
        // \Views\Shared\Components\LogComponent\Default.cshtml
        // Musi se jmenovat default.cshtml a musí být přesně na tomto místě
        return View(log);
    }
}



// Vypislogu.cshtml

// Vyvoláme v kodu takto
@foreach(var log in Model.Logs)
{
    //Vytváříme pro každy 
    Component.InvokeAsync("ExercisesComponent",log)
}

// \Views\Shared\Components\LogComponent\Default.cshtml

@Model Log

<div>
	Akce: @("Sudo " + Model.Action)
<div/>
<div>
	Akce: @Model.Message
<div/>
            
// = Docílily jsme uplně toho samého jako s foreachem, 
ale nyní mužeme ještě třeba do logu něco přidat.

// Vypislogu.cshtml
==
Akce: Sudo Pokus
Text: Pokud o pokus Pokus
Akce: Sudo neco
Text: Proste neco
...


    
ViewBag ViewData
Viewbag a ViewData nám umožnuje ukládat cs objekt do nějaké proměné, kterou mužeme zobrazit na webu.
Oba dělají uplně to stejný, ale mají jiný zápis
    

// HomeController

public IActionResult Vypislogu()
{
    List<Log> logy = context.tbLogs.ToList();
        
    ViewData["PocetLogu"] = logy.Count;

    ViewBag.PocetLogu = logy.Count;

    return View(new LogPage(logy, DateTime.Now()));

}

// Vypislogu()

<div>@ViewData["PocetLogu"]<div/>
                
<div>@ViewBag.PocetLogu<div/>
    
==

2

2


// Uplně stejný výsledek
    
Více informací: learn.microsoft.com (dole)