quinta-feira, 24 de setembro de 2015

Novo site pessoal Charles Oliveira

Olá pessoal, venho informar que já encontra-se publicado meu novo site pessoal, lá você poderá conhecer minha história profissional, minhas experiências e entre outros, em breve estarei realizando novas alterações e a medida que forem sendo feitas irei postar aqui.

 No próximo post irei mostrar quais tecnologias eu usei e como foram implementadas. Caso tenham algum comentário por favor escrevam, ficarei muito agradecido com sua colaboração.

Acessem: Charles Oliveira

terça-feira, 18 de agosto de 2015

GridView em ASP.NET MVC com Itens Por Página

Neste post irei mostra com implementar a listagem de quantidade de itens por páginas no componente Grid.Mvc. Por padrão ele tem paginação, filtro e ordenação, porém não disponibilizar uma opção para informar a quantidade de itens a serem exibidos, a não ser de forma estática no backend.

Desenvolvi uma solução que está atendendo muito bem as necessidades dos projetos que tenho trabalhado e espero que possa ajudar algum de vocês também.

Toda a documentação de como usar este componente em seu projeto, poder encontrado aqui. O intuito deste poste é mostra apenas inclusão de uma lista para selecionar a quantidade de itens que deverá ser exibida pelo componente.

Após você incorporar o Grid.Mvc em seu projeto é hora de criamos nossa estrutura.

Primeiro devemos criar um classe que irá interceptar as execuções das Actions que contenham dados para GridMvc, isso se dará em forma de anotação, veja:

public class GridMvcAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var controller = (Controller)filterContext.Controller;
        var rd = filterContext.RouteData;
        var request = filterContext.HttpContext.Request;
        var model = controller.ViewData.Model as IQueryable;
 
        var count = model != null ? model.Count() : 0;
 
        int pagesize, page;
 
        if (!int.TryParse(request.Params.Get("grid-page-size"), out pagesize))
            pagesize = GridMvcFilter.DefaultPagesize;
 
        if (!int.TryParse(request.Params.Get("grid-page"), out page))
            page = 1;
 
        var tbFilter = new GridMvcFilter
        {
            Id = rd.Values["id"] as string,
            Action = rd.GetRequiredString("action"),
            Controller = rd.GetRequiredString("controller"),
            GridPage = page,
            GridPageSize = pagesize,
            GridFilter = request.Params.Get("grid-filter"),
            GridOrd = request.Params.Get("grid-ord"),
        };
 
        controller.ViewBag.ItemsPerPage = pagesize;
        controller.ViewBag.ListDropDown = GetListsDropDown(tbFilter, count);  
 
    }
    private static IEnumerable GetListsDropDown(GridMvcFilter tbFilter, int max)
    {
 
        var itemSelected = tbFilter.GridPageSize ?? GridMvcFilter.DefaultPagesize;
        var list = new List();
        const int defaultPageSize = GridMvcFilter.DefaultPagesize;
 
        if (max <= defaultPageSize)
            list.Add(new SelectListItem
            {
                Value = SetLink(tbFilter, defaultPageSize.ToString(CultureInfo.CurrentCulture)),
                Text = defaultPageSize.ToString(CultureInfo.CurrentCulture),
                Selected = true
            });
        else
        {
            for (var i = defaultPageSize; i < max + defaultPageSize; i += defaultPageSize)
            {
                list.Add(new SelectListItem
                {
                    Value = SetLink(tbFilter, i.ToString(CultureInfo.CurrentCulture)),
                    Text = i.ToString(CultureInfo.CurrentCulture),
                    Selected = itemSelected == i
                });
            }
        }
        return list;
    }
 
    private static string SetLink(GridMvcFilter tblParams, string value)
    {
        var filter = tblParams.GridFilter != null ? tblParams.GridFilter.Split(',') : new string[] { };
 
        var gridfilter = "";
        if (filter.Length <= 0)
            return String.Format("/{0}{1}?grid-page={2}&grid-page-size={3}{4}{5}",
                tblParams.Controller,
                (!string.IsNullOrEmpty(tblParams.Action) ? "/" + tblParams.Action : "") +
                (!string.IsNullOrEmpty(tblParams.Id) ? ("/" + tblParams.Id) : ""),
                tblParams.GridPage,
                value,
                tblParams.GridOrd != null ? ("&grid-ord=" + tblParams.GridOrd) : "",
                gridfilter);
 
        gridfilter = filter.Where(item => item.Length > 0).Aggregate(gridfilter, (current, item) => current + ("&grid-filter=" + item));
 
        return String.Format("/{0}{1}?grid-page={2}&grid-page-size={3}{4}{5}",
           tblParams.Controller,
           (!string.IsNullOrEmpty(tblParams.Action) ? "/" + tblParams.Action : "") + (!string.IsNullOrEmpty(tblParams.Id) ? ("/" + tblParams.Id) : ""),
           tblParams.GridPage,
           value,
           tblParams.GridOrd != null ? ("&grid-ord=" + tblParams.GridOrd) : "",
           gridfilter);
    } 
}

Crie também uma classe que conterá a estrutura de filtros, como segue:
public class GridMvcFilter
{
   public const int DefaultPagesize = 10;
   public string Id { get; set; }
   public string Controller { get; set; }
   public string Action { get; set; }
   public string GridOrd { get; set; }
   public string CurrentFilter { get; set; }
   public string GridFilter { get; set; }
   public int? GridPage { get; set; }
   public int? GridPageSize { get; set; }
}
Agora faremos uma pequena alteração no arquivo "_GridPager.cshtml", este arquivo é responsável por renderizar o conteúdo de rodapé do grid. Acrescente este trecho de código, com isso será possível resgatar a lista de páginas gerada pela classe de anotação criada acima.
@{
    var itemsPerPageList = (IEnumerable)ViewBag.ListDropDown;
}

No final do aquivo acrescente o código que irá renderizar a lista, fique a vontade para estilizar.
  @if (Model.ItemsCount > 0)
        {
            
                Página @Model.CurrentPage de @Model.PageCount
                - Exibindo até @Html.DropDownList("grid-page-size", itemsPerPageList, new { @onchange = "location = this.value" })  de @Model.ItemsCount Registros
            
        }

Por a ativação da anotação em uma Action que deve renderizar um Grid.
[GridMvcAttribute]
public ActionResult Index()
{
   var carList = new List();
   for (int i = 1; i <= 50; i++)
   {
      carList.Add(new Car { Id = i, Model = "Model 0" + i, Year = 2010 + i });
   }
   return View(carList.AsQueryable().OrderBy(a=>a.Model));
}

Por último devemos informar ao grid que desejamos utilizar paginação e a quantidade de itens na páginas que desejamos ver.
@Html.Grid(Model).Columns(col =>
{
    col.Add(c => c.Id).Titled("Id").Filterable(true);
    col.Add(c => c.Model).Titled("Model");
    col.Add(c => c.Year).Titled("Year");
}).WithPaging((int)ViewBag.ItemsPerPage).Sortable(true).Filterable(true).WithMultipleFilters()

Atente para o método "WithPaging", nele passamos como parâmetro a variável que foi configurada no na classe GridMvcAttribute.
Todo o projeto é possível encontrar no meu github.

quinta-feira, 13 de agosto de 2015

Bind com tipos nulos

Hoje pela manhã, ao acessar meus e-mails, havia um de um grupo do linkedin que eu sigo com uma postagem sobre problemas ao trabalhar com tipos anuláveis em ASP.NET MVC. Há algum tempo, pouco mais de dois meses passei por este mesmo problema. Um campo DateTime que era anulável, e quando eu tentava receber o valor através de um POST, o mesmo não aparecia no modelo.

Vamos a solução, imagine a seguinte classe:

public class Compras{
   public DateTime? Data { get; set;}
}
O controller que recebera o post tem a seguinte Action;

[HttpPost]
public ActionResult Salvar(Compras compras){
    //....
}

Ao realizar o post, a propriedade Data não conecta no objeto do tipo Compras criado pelo DefaultModelBinder (responsável por fazer a tradução da requisição HTTP para objetos complexos  compatíveis no .NET Framework) do ASP.MVC.

A solução é criar nosso próprio Binder, da seguinte maneira:

No seu projeto web crie uma classe implementando o interface IModelBinder que irá interceptar as requisições HTTP e detectar a propriedade anulável.
public class DateTimeBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var valueResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);

        var modelState = new ModelState { Value = valueResult };
        object valorAtual = null;

        try
        {
            valorAtual = Convert.ToDateTime(valueResult.AttemptedValue, System.Globalization.CultureInfo.CurrentUICulture);
        }
        catch (FormatException e)
        {
            modelState.Errors.Add(e);
        }

        bindingContext.ModelState.Add(bindingContext.ModelName, modelState);
        return valorAtual;
    }
}
No arquivo de projeto chamado Global.asax sobrescreva o método Init informando o novo binder, como segue:
public override void Init()
{
    base.Init();
    ModelBinders.Binders.Remove(typeof(DateTime));
    ModelBinders.Binders.Add(typeof(DateTime), new DateTimeBinder());
}
Desta forma agora você poder persistir suas propriedades anuláveis.
Você pode baixar um projeto de exemplo aqui no meu GitHub.
Segue link de referência: John Reilly

O que você vai encontrar.

Este é o primeiro post deste blog, e é o meu segundo neste tipo de ambiente, a primeira vez que fiz algo desse tipo foi durante a faculdade, na época foi um requisito para concluir uma disciplina. Bem, aqui irei escrever sobre problemas que eu encontro no meu dia-a-dia no trabalho, como sou programador, logo, serão problemas da natureza desta profissão, mais especificamente sobre ASP.NET MVC, SQL Server, Entity Framework, padrões de projetos em geral tecnologias para desenvolvimento.