úterý 18. listopadu 2014

Zábavní parky okolo ČR

Bohužel nám v ČR chybí pořádný zábavní park a tak se musí vždy do zahraničí. Tady je přehledná mapka zábavních parků v Evropě - ty lepší jsou zvýrazněny hvězdičkou.  Snažil jsem se zahrnout všechny parky, které mají něco, co alespoň trochu připomíná horskou dráhu.

Jak je vidět, naprostá většina parků leží v Německu - zejména asi jeden z nejlepších parků v Evropě Europa Park.


Ne všechny parky v přehledu stojí za návštěvu, - například bych varoval před polským parkem Wesole Miasteczko  - je to asi tak nejhorší park, co jsme kdy navštívil, díky neschopnosti obsluhy neskutečné čekací doby i když byl park prázdný. U jiných parků je třeba zvážit i vhodný věk na návštěvu. Rakouský Family Park se hodí spíše pro menší děti, německý Legoland asi nadchne děti do 10ti let a pak už je to horší a tak podobně. 






pondělí 17. listopadu 2014

Feraty u jezera Lago di Garda 1 - Colodri a Drena


Colodri

Naše první ferata u jezera a velmi pěkná - k příznivému dojmu přispěl i pěkný slunečný den. 



Výstup stojí za to, postupně se odkrývá údolí s řekou a po zdolání posledního úseku se otevře výhled na hrad Arco na sousedním vrcholu a také dále k jezeru.

čtvrtek 6. listopadu 2014

Stránkování v MVC

Tenhle článeček je o stránkování záznamů v MVC trochu jinak - tak, aby jednotlivé části (controller's actions, models, views) zůstaly co nejvíce jednoduché.

Zdrojový kód je dostupný zde.

Models

Aby to nebylo moc složité, bude se zobrazovat seznam jmen, tedy jako základní třída  nám poslouží toto:
public class UserViewModel
{
 public string FirstName { get; set; }
 public string LastName { get; set; }
}

Pro zobrazení seznamu bude sloužit generická třída - takže ani tento příklad nebude pevně svázán s třídou UserViewModel, ale generickou třídu budeme moci použít s jakoukoliv třídou, z níž chceme zobrazovat data.
public interface IItemListInfo
{
 int TotalItems { get; }
}

public class ItemListViewModel<T> : IItemListInfo
{
 private IEnumerable<T> items;
 private int totalItems;

 public ItemListViewModel(IEnumerable<T> items, int totalItems)
 {
  this.items = items;
  this.totalItems = totalItems;
 }
 public IEnumerable<T> Items { get {return this.items;} }
 public int TotalItems { get { return this.totalItems; } }
}

a ještě musíme mít třídu, která bude držet "stránkovácí" informace:
public class PagingViewModel
{
 public int PageNumber { get; set; }
 public int PageSize { get; set; }
 public int Pages {get;set;}
}
Objekt této třídy bude vlastně jen držet číslo aktuální stránky, velikost stránky a celkový počet stránek.

Controller - poprvé

Akce v kontroleru bude jednoduchá - hlavním úkolem je načíst daný počet dat (=počet záznamů na stránku)  pro danou stránku (počet stránek)


public ActionResult Index(PagingViewModel paging)
{
 ItemListViewModel<UserViewModel> model = this.GetUsers(paging.PageSize, paging.PageNumber);

 return View(model);
}


Views

Ve view dojde k zrendrování informací a i k vykreslení navigační části. První view je docela jednoduché a vykreslí informace o uživateli - pro vykreslení navigační části pak předá řízení zpět do kontroleru a zavolá akci "Paging"




@using MvcPagingExample.Models;

@model ItemListViewModel<UserViewModel>
@{
    ViewBag.Title = "Home Page";
}
<div class="list">
    <h2>List of Users</h2>

    <table>
        <thead>
            <th width="120px">First name</th>
            <th width="120px">Last name</th>
        </thead>
        @foreach (UserViewModel user in Model.Items)
        { 
            <tr>
                <td>@user.FirstName </td>
                <td>@user.LastName</td>
            </tr>
        }
    </table>
    <br/>
    @{Html.RenderAction("Paging");}
</div>



Controller - podruhé

Tato metoda může být použita pro vykreslení stránkování libovolného seznamu - odpovídající view jen využívá javascript pro ajax volání zpět na server a vrácenou hodnotou nahrádí stávající obsah:


[ChildActionOnly]
public ActionResult Paging(PagingViewModel paging)
{
	return PartialView(paging);
}

a view:


@using MvcPagingExample.Models;

@model PagingViewModel
<script type="text/javascript">
    $(document).ready(function () {
        jQuery("a").click(function () {
            var $anchor = jQuery(this);
            var url = $anchor.closest('.ajaxPaging').attr("data-source");
            jQuery.get(
                url,
                { PageNumber: $anchor.attr("rel")},
                function (data) {
                    jQuery(".list").replaceWith(data);
                });
        });
    });
</script>

<div class="ajaxPaging" data-source="@Request.Url.AbsolutePath">
    @NaviLink(active: Model.PageNumber > 1, targetPageNumber: 1, label: "first")
    @NaviLink(active: Model.PageNumber > 1, targetPageNumber: (Model.PageNumber - 1), label: "previous")
    <b>page @Model.PageNumber of @Model.Pages</b>
    @NaviLink(active: Model.PageNumber < Model.Pages, targetPageNumber: (Model.PageNumber + 1), label: "next")
    @NaviLink(active: Model.PageNumber < Model.Pages, targetPageNumber: Model.Pages, label: "last")
</div>

@helper NaviLink(bool active, int targetPageNumber, string label)
{
    if (active)
    {
    <a href="#" rel="@targetPageNumber">@label</a>
    }
    else
    { 
    @label
    }
}


Prvotní nastavení

Zbývá ještě ošetřit případ, kdy při prvním volání akce není žádné stránkování nastaveno.  K tomu slouží atribut třída, která dědí z třídy ActionFilterAttribute a která nabízí dvě metody - jednu spouštěnou před provedením vlastní akce kontroleru (OnActionExecuting) a druhou, která se provadí  po vykonání akce v kontroleru (OnActionExecuted).



public override void OnActionExecuting(ActionExecutingContext filterContext)
{
	var paging = filterContext.ActionParameters.Select(p => p.Value as PagingViewModel).Where(f=> f !=null).FirstOrDefault();

	if (paging != null)
	{
		paging.PageSize = PageSize;
		filterContext.RouteData.Values.Add("PageSize", this.PageSize);

		if (paging.PageNumber == 0)
		{
			filterContext.RouteData.Values.Add("PageNumber", 1);
			paging.PageNumber = 1;
		}
	}
	base.OnActionExecuting(filterContext);
}

Nejprve se metoda pokouší najít hodnotu parametru předávaného metodě kontroleru - tedy PagingViewModel.  Pokud takový parametr nenajde, tak jej vytvoří a nastaví velikost stránky a první stránku jako aktuální. Zároveň tyto hodnoty vloží i do kolekce RouteData. Tato kolekce je MVC používáná při bindování a pokud tedy budeme později volat metodu Paging, tak MVC použije data z této kolekce pro vytvoření parametru (instance třídy PagingViewModel) předávaného do této metody.

Po spuštění metody se naplní kolekce a zároveň se zjistí, kolik záznamů je celkem k dispozici. Což je ten správný okamžik pro spuštění metody OnActionExecuted, která vypočte celkový počet stránek a získá tak poslední hodnotu, kterou je nutno uložit do kolekce RouteData, aby MVC mohlo později, při volání metody Paging, vytvořit plnohodnotnou instanci třídy PagingViewModel.



public override void OnActionExecuted(ActionExecutedContext filterContext)
{
	var model = filterContext.Controller.ViewData.Model as IItemListInfo;

	if (filterContext.HttpContext.Request.IsAjaxRequest())
	{
		ViewResult result = filterContext.Result as ViewResult;
		filterContext.Result = new PartialViewResult() { TempData = result.TempData, View=result.View, ViewData=result.ViewData, ViewEngineCollection=result.ViewEngineCollection};
	}
						
	if (model != null)
	{
		filterContext.RouteData.Values.Add("Pages", (int) Math.Ceiling( (double) model.TotalItems/this.PageSize));
	}

	base.OnActionExecuted(filterContext);
}

Můžete si také všimnout, že je kontrolován typ příchozího volání a pokud se jedná o Ajax volání, je výsledek změněn na PartialView - takže se rendreju pouze view odpovídající danému kontroleru a master view je ignorováno - vrací se tak pouze zrendrovaná tabulka a nikoliv celá stránka.


Tento atribut je pak použit pro dekorování akce  a zároveň nastavuje velikost stránky:


[Paging(PageSize = 5)]
public ActionResult Index(PagingViewModel paging)
{
	ItemListViewModel<UserViewModel> model = this.GetUsers(paging.PageSize, paging.PageNumber);

	return View(model);
}

Může se použít na libovolnou akci, která vyžaduje pro své výsledky stránkování. Vývojář se o stránkování nemusí starat a v kontroleru se tedy může soustředit pouze na získání dat.






pondělí 3. listopadu 2014

Proč si nekupovat nosič od Atery (Atera Strada 3 DL)


Minulý rok jsem si koupil nosič na kola Atera Strada 3 DL s rozšířením na čtvrté kolo. S nosičem jsem byl celkem spokojen, dokud nebyl při couvání poškozen a vyvstala nutnost opravy - jednalo se o výměnu jednoho zadního dílu, který zajišťuje blokování pohyblivé části.

A s překvapením jsem zjistil, že vlastně žádný servis těchto poměrně drahých výrobků u nás neexistuje. Našel jsem sice nějaký soukromý servis, který se značkou Atera zabývá, ale tam mne jen politovali s tím, že jim to mohu poslat a oni budou čekat, až nějaký jiný neš´tasník hodí svůj nosič do šrotu a oni tak získají potřebnou součástku - Atera totiž náhradní díly nerada dodává. Tomu se mi nechtělo věřit, přeci jen je to výrobek v cenové relaci kolem €500 a tak jsem napsal přímo výrobci, popsal svůj problém, přiložil fotografie a už za pár dnů jsem měl odpověď:


Hello, pleace contact your dealer.....


Takže jsem nelenil a požádal o seznam dealerů a během dne obdržel kontakt na firmu Neumann a Elit CZ.

Z výše dvou uvedených Elit CZ vůbec nereagoval, u Neumanna se ozval jejich pracovník a začala zdlouhavá výměna mailů - když už se zdálo, že je díl úspěšně objednán, ozval se jejich pracovník s tím, že firma Atera není schopna díl dodat......

Naštěstí měl i řešení - měli skladem použitý poškozený nosič, který jim tam zřejmě nějaký méně trpělivý zákazník nechal a u kterého byl daný díl v pořádku a tak mi nabídl jeho zaslání jen za cenu poštovného - a tak jsem měl po třech měsících konečně nosič opět funkční - díky nadstandardní ochotě pracovníka firmy Neumann.

A poučení?

Výrobek od firmy Atera si už nikdy nekoupím, jakýkoliv - firma, která není schopna dodat náhradní díl (asi chce zákazníka, aby si koupil nový výrobek) je špatná firma.

čtvrtek 30. října 2014

Ferraty u Lago di Garda s dětmi na vlastní pěst

Při zařizování letošní krátké dovolené v Itálii jsem si uvědomil, že jsem vlastně  nikdy nepoužil služeb  cestovních kanceláří - tedy mimo prolistování katalogů, kde se občas dá najít pěkný tip na místo stojící za návštěvu. Vlastně ani nevím, co by mi nabídla a vyhovuje mi i volnost, které mi cestování "na vlastní pěst" poskytuje i to, že takto  naplánována cesta vyjde levněji

Například na letošní podzimní prázdniny jsem si naplánoval výlet k jezeru Lago di Garda s tím, že si prolezeme zajímavé ferraty v okolí.

středa 22. října 2014

Jak navštívit zábavní parky se slevou 85%


Název je trochu nadnesený, ale v létě roku 2013 se prodávala ve vídeňském Prátru roční předplacená rodinná vstupenka 3+1 (pro čtyři osoby) za pouhých €185. Jen pro porovnání, v letošním ceníku je již tato vstupenka za €297 - na druhou stranu má ale navíc bezplatné parkování v Legolandu a Heide parku a ještě Express pass do těchto dvou parků (přednostní vstupenku na atrakce).


Nově se také nabízí i levnější varianta, která nemá parkování, express pasy, vstup do Gardalandu a už ani do dánského Legolandu za cca €240.


Po roce platnost vstupenky vypršela a nastal čas trochu počítat a najít, kde jsme všude byli a kolik by to stálo, pokud bychom si kupovali jednotlivé vstupy - přičemž jsem počítal s tím, že by se lístek kupoval s předstihem on-line. Přímo na pokladnách jsou pak ceny vyšší o minimálně 20%.

Výsledek vypadal takto:

  • €90 za 3 * Heide Park
  • €80 za 2 * Legoland Billund
  • €75 za 3 * Legoland Gunzburg
  • €30 za 1 * Gardaland
  • €30 za 1 * Legoland Discovery Center Berlin a Oberhausen
  • €5   za 1 * Adventure Park Oberhausen
  • €45 za 1 * Sea Life Oberhausen, Berlin,Timmendorfen Strand
  • €30 za 1 * Madam Tussauds Viden a Berlin
  • €15 za 1* Hamburg Dungeon 15


Ne všechny karty byly používány stejně, takže jsme celkově uskutečnili návštěvy za €1285 - a za karty zaplatili původně €185 - takže je to sleva ve výši 85%. Navíc jsme využili i slevy na kemp  v německém  Legolandu - ten je zážitkem zejména pro menší děti. Ale ani ty starší se nenudili, jak je vidět na tomto obrázku:

.

Ceny karet jsou na stránkách Merlin Pass a vyplatí se sledovat, kde jsou jaké slevy - karty také bývají při objednávání v únoru a březnu levnější. Jsem sám zvědavý, jak upraví ceník na rok 2015 - ceník na rok 2014 už rozhodně nebyl tak výhodný jako na rok 2013. Vstupenka platí následujících 365 dnů po koupi včetně všech výhod a to i při změně ceníku.

pátek 10. října 2014

Kde zaparkovat u Hohe Wand

Hohe Wand je masív, který se nachází kousek pod Vídní a poskytuje několik ferat - s bonusem ve formě vyhlídky z terasy Skywalk.

Místo jsme navštívíli začátkem října - bylo sice pošmourno, ale i přes tohle počasí jsme si to užili. Feráty jsou to opravdu lehké a dají se zvládat bez zajištění - ostatně většina lidí co jsme potkali ani žádné neměla :-)