quinta-feira, 18 de outubro de 2012

Entity Framework Json Serializer


Available at codeplex, a helper class to serialize EntityFramework entities with Asp.NET MVC JsonResult. This helper class solve the "Circular Reference" problem.
For more information: EFJson.

Entity Framework Json Serializer

Está disponível para download uma classe para serializar classes do EntityFramework em conjunto com o JsonResult do Asp.NET MVC. Esta classe evita o erro de referência circular.
Para mais detalhes: EFJson.

sexta-feira, 10 de fevereiro de 2012

Problema IE, IFRAME e PDF

Ontem tive um problema completamente inesperado.
Eu estava tentando mostrar um PDF dentro de um  <iframe>. Este era meu código:

<iframe src="algumdoc.pdf" width="100%" height="100%"><iframe>

Como tudo na WEB testei no FireFox e depois no Chrome, funcionou perfeitamente. Quando fui testar no IE, ele simplesmente travou e tive que fechá-lo.
Testei na máquina de mais algumas pessoas o mesmo acontecia.
Culpa do IE? Culpa da Adobe? Não sei, mas precisava resolver o problema.
Após algumas pesquisas achei uma outra maneira de mostrar um arquivo PDF:

<embed src="algumdoc.pdf" width="100%" height="100%"></embed>

A solução é muito simples, porém levei algumas horas para achá-la.

sábado, 1 de outubro de 2011

Teched 2011

Fui ao teched este ano e estou aqui para contar o que achei do evento.
O evento é bem organizado em questão de infraestrutura, mas achei alguns pontos negativos o que desanima muito.
O primeiro motivo é a questão das coisas nos EUA ocorrerem antes . Com isso, se você é uma pessoa que costuma estudar bastante você não encontrará nada de novo nas apresentações, e até mesmo nada que complemente o que você ja sabe.
O segundo motivo são as pessoas escolhidas para apresentar a tecnologia, apesar de serem MVP etc, isso não significa que são didáticos, por isso, de mais de dez palestras que eu fui, apenas duas foram bem apresentadas, com uma certa didática. Vale a pena elogiar os palestrantes dessas duas palestras que foram Giovani Bassi, Guadalupe Casuso e Lalo Steinmann.
A minha opinião vem das palestras de desenvolvimento, mas ouvi muitas pessoas pela parte de infra reclamando também pela má qualidade das palestras.
Não quero fazer desta postagem uma crítica, mas apenas um aviso para as pessoas que pretendem ir aos próximos e possuem o perfil citado acima não se desaponte, afinal o preço da inscrição não é nada barato, e com toda sinceridade, o evento não vale o que se paga.

terça-feira, 7 de junho de 2011

Entity Framework NavigationProperties e a Interface INotifyPropertyChanging

O WPF assim como o Silverlight usam o evento PropertyChanging da interface INotifyPropertyChanging para atualizar os bindings dos controles.
As entidades do EntityFramework ja tratam isso pra você, por isso você não tem que se preocupar, veja um exemplo:

[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=true)]
[DataMemberAttribute()]
public string Nome
{
     get
    {
           return _Nome;
     }
     set
    {
           OnNomeChanging(value);
            ReportPropertyChanging("Nome");
           _Nome= StructuralObject.SetValidValue(value);
           ReportPropertyChanged("Nome");
           OnNomeChanged();
      }
}

Porém, quando se há um relacionamento como, por exemplo, uma pessoa possui várias compras, e você está trabalhando com a entidade Compra, se você fizer:

compra.Pessoa = pessoa;
e caso o seu TextBox esteja com o binding para o Nome da Pessoa relacionado:

<TextBox Text="{Binding Pessoa.Nome}" />

o texto do TextBox não será atualizado porque não há eventos que notifique essa mudança, veja como é implementado o get e o set de Pessoa:

[XmlIgnoreAttribute()]
[SoapIgnoreAttribute()]
[DataMemberAttribute()]
[EdmRelationshipNavigationPropertyAttribute("Model", "FK__Pessoa_Compra", "Pessoa")]
public Pessoa Pessoa
{
      get
      {
             return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Pessoa>("Model.FK__Pessoa_Compra", "Pessoa").Value;
       }
       set
      {
            ((IEntityWithRelationships)this).RelationshipManager.GetRelatedReference<Pessoa>   ("Model.FK__Pessoa_Compra", "Pessoa").Value = value;
       }
}

Por sorte, o EntityFramework possui eventos que você pode utilizar para reverter esta situação.
Para toda referência há uma ou mais propriedades que se relacionam entre as tabelas, e com isso elas também existem nas entidades do EntityFramework. No meu caso há uma coluna chamada IdPessoa do tipo int na entidade Compra. Essas colunas são atualizadas assim que você atribui a nova pessoa na referência, desta maneira se a pessoa tiver o Id = 15, o compra.IdPessoa também será 15 quando eu fizer:
compra.Pessoa = pessoa, e todos os eventos PropertyChanging e PropertyChanged serão disparados.
Dessa maneira podemos usar o evento parcial dessa coluna para notificar nossa interface da mudança dos valores:

public partial class Compra
{
      partial void OnIdPessoaChanged()
     {
           OnPropertyChanged("Pessoa");
      }
      partial void OnIdPessoaChanging(int value)
     {
           OnPropertyChanging("Pessoa");
     }
}

Repare que a string passada como parâmetro é Pessoa que é o nome da nossa propriedade de relacionamento.
Note também que esta classe deve estar no mesmo namespace da classe gerada pelo EntityFramework.

Até a próxima.

quinta-feira, 2 de junho de 2011

WPF Calendar com BoldedDates

O controle Calendar do WPF é muito parecido com o MonthCalendar do WindowsForms. Porém como muito se acontece no WPF você tem que abrir a cabeça quando quer adicionar uma funcionalidade mesmo que ela fosse muito fácil no WindowsForms. Isso se deve ao fato do WPF possui seus controles muito mais poderosos, porém poder não quer dizer mais simples de ser utilizado.
Para fazer a mesma funcionalidade do BoldedDates do MonthCalendar você tem que trabalhar com CalendarDayButtonStyle em conjunto com o IValueConverter.
Caso você ja saiba as datas que devem ficar bold, você pode fazer da seguinte maneira:

1) Declare seu convert:

namespace WPFBoldDates
{
      public class BoldDateConverter : IValueConverter
     {
             public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                    if(System.Convert.ToDateTime(value) == new DateTime(2011, 06, 06))
                    {
                             return FontWeights.Bold;
                    }
                    return FontWeights.Normal;
             }

              public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
             {
                       return value;
             }
      }
}
 
2) Configura o style:
 
<Window x:Class="WpfApplication1.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:my="clr-namespace:WPFBoldDates"
                Title="MainWindow" Height="350" Width="525">
      <Window.Resources>
           <my:BoldDateConverter x:Key="boldConverter" />
      </Window.Resources>
      <Grid>
            <Calendar x:Name="calendario">
                  <Calendar.CalendarDayButtonStyle>
                    <Style TargetType="CalendarDayButton">
            <Setter Property="FontWeight" Value="{Binding Converter={StaticResource boldConverter}}" />
                    </Style>
                  </Calendar.CalendarDayButtonStyle>
            </Calendar>
     </Grid>
</Window>

Pronto, o dia 06/06/2011 ficará em negrito.

Caso queira trabalhar com datas dinâmicas você pode utilizar um CollectionViewSource.

1) Adicione um recurso para seu Window do tipo CollectionViewSource e passe ela como parâmetro do seu binding:

<Window x:Class="WpfApplication1.MainWindow"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:my="clr-namespace:WPFBoldDates"
                Title="MainWindow" Height="350" Width="525">
      <Window.Resources>
           <my:BoldDateConverter x:Key="boldConverter" />
           <CollectionViewSource x:Key="dates" />
      </Window.Resources>
      <Grid>
            <Calendar x:Name="calendario">
                  <Calendar.CalendarDayButtonStyle>
                    <Style TargetType="CalendarDayButton">
            <Setter Property="FontWeight" Value="{Binding Converter={StaticResource boldConverter}, ConverterParameter={StaticResource dates}}" />
                    </Style>
                  </Calendar.CalendarDayButtonStyle>
            </Calendar>
     </Grid>
</Window>

2) No construtor do seu Window inicialize o CollectionViewSource:

public partial class MainWindow : Window
{
       public MainWindow()
      {
             InitializeComponent();
             List<DateTime> dates = new List<DateTime>();
             // Só para demonstração, você pode optar por ir no banco de dados
             dates.Add(new DateTime(2011, 6, 6));
            CollectionViewSource source = FindResource("dates") as CollectionViewSource;
            source.Source = dates;
       }
}
 
3) Para finalizar ajuste seu IValueConverter:
 
      public class BoldDateConverter : IValueConverter
     {
             public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                    List<DateTime> dates = (parameter as CollectionViewSource).Source as List<DateTime>;
                    if(dates.Contains(System.Convert.ToDateTime(value)))
                          return FontWeights.Bold;

                    return FontWeights.Normal;
             }

              public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
             {
                       return value;
             }
      }
}

Como você pode ver, um tanto grande nosso esforço, porém não se limite apenas a usar o bold. Com style vocde formatar seu botão completamente para que ele atenda suas necessidades.

Até a próxima.

quarta-feira, 1 de junho de 2011

WPF DataGrid e DocumentViewer

Acabo de passar por mais um problema que gostaria de compartilhar com vocês.
Desta vez o problema foi tentar mostrar no DocumentViewer um DataGrid com paginação e tudo.
Como é de se esperar não estou aqui hoje para explicar passo a passo o código, estou aqui para dar uma solução para as pessoas que possuem o mesmo problema.
Criei uma classe chamada PrintExtensions.
Dentro dela há duas funções, uma para fazer uma cópia do DataGrid e outra para mostrar no DocumentViewer qualquer FrameworkElement, esta segunda função eu retirei do Blog do Telerik.

O arquivo com o código encontra-se aqui.

Para usar a função apenas faça:

DocumentViewer document = new DocumentViewer();
document.Document = PrintExtensions.PrintDataGrid(dataGrid1, new PrintDialog());

Espero ter ajudado e até a próxima.

quinta-feira, 10 de fevereiro de 2011

WPF x Windows Forms

Desde o .NET Framework 3.0 a Microsoft introduziu o Windows Presentation Foundation (WPF), mas o que é essa nova tecnologia? Por que a Microsoft investirá nela e tentará substituir de vez o Windows Forms?
Aqui estão as cinco mudanças que fazem a diferença do WPF contra o Windows Forms.

Controles: o Windows Forms roda em cima do GDI que é a integração visual do Windows desde seu primórdio, ja o WPF roda em cima do Directx, uma camada mais abaixo, onde assim ganha em performance.

Programação 2D: o Windows Forms precisa da dll System.Drawing ja o WPF não, afinal ela ja roda em Directx certo?

Programação 3D: esse é o maior ponto, quem o WPF usa mesmo? Directx? Hum interessante, então eu preciso aprender o WPF e programar em cima dele e ele tranformará na linguagem correta para o Directx correto? Sim. Ja o Windows Forms você precisará aprender programar em Directx mesmo.

Documentos: WPF ja possui uma dll nativa, ja Windows Forms você precisará de dll de terceiros ou trabalhar manualmente com PDF, txt etc.

Mídia: no Windows Forms é necessário a dll do MediaPlayer, ja no WPF ele possui uma dll nativa com os mesmos conceitos dos outros tópicos.

Esses são as cinco melhoras do WPF em relação ao Windows Forms. Sem falar em melhoras como Data Binding e outros pontos. A mudança não é fácil, mas ela é inevitável, quais foram as melhoras do Windows Forms no .NET 4? O que a Microsoft trouxe de novidade? Sinceramente não vi nenhuma, no Training Kit somente veio exemplos usando Ribbon em MFC, sim eu disse MFC e não Windows Forms, não veio se quer um lab de Windows Forms.
Porém é hora de abrir a mente e estudar essa nova tecnlogia, WPF é muito poderoso basta você querer aprender e usar esse poder todo.

sábado, 2 de outubro de 2010

Auto complete em Asp.NET MVC

Olá pessoal, após muuiiiiitttooo tempo estou aqui novamente. Estou envolvido em um projeto que está tomando bastante meu tempo, mas estou bem satisfeito porque tivemos um ótimo resultado, e muitas coisas novas estão por vir. É um portal que traz o teatro até os internautas, e lugares onde provavelmente as peças nunca iriam chegar, agora têm-se a possibilidade de assistí-las, fico feliz por estar ajudando a levar a cultura para novos lugares. Caso tenham interesse, visite o portal http://www.cennarium.com/

Vamos ao problema: fazer um autocomplete que quando a pessoa comece a digitar ele vá até o servidor e traz alguns resultados.
Tecnologia usada: ASP.NET MVC 2 e Entity Framework.

Eu fiquei impressionado com a facilidade que tive de fazer usando post do jquery e Json do Asp.net mvc.

Vamos aos passos:

1) No seu controller, crie uma ação para retornar os dados de sua pesquisa, e faça que ela receba apenas quando a requisição for POST. No meu caso vou chamar o controller de AutoComplete, e minha ação chamará Cars, pois nela retornarei apenas o auto-complete para carros:

[HttpPost]
public ActionResult Cars(string search)
{
      string[] cars = carList.Where(c => c.Name.ToLower().StartsWith(search)).Select(c => c.Name).ToArray();
      return Json(cars);
}

Vamos explicar o que fiz na ação: apenas consulto meu repositório (nesse caso um fake repositório), e retorno um array de string (nomes dos carros encontrados na pesquisa), esse array eu retorno no formato de Json para minha View, sim, é o que você está imaginando, você pode retornar qualquer objeto .NET por Json, e ele converte tudo para você automaticamente.

Apenas por questão de teste, crie uma classe na sua pasta Models da seguinte maneira:

public class Car
{
        public string Name{get;set;}
}

E no construtor do seu controller adicione:

public AutoCompleteController()
{
     carList = new List<Car>();
     carList.Add(new Car { Name = "Ferrari" });
     carList.Add(new Car { Name = "Gol" });
     carList.Add(new Car { Name = "KA" });
     carList.Add(new Car { Name = "Vectra" });
     carList.Add(new Car { Name = "Hilux" });
     carList.Add(new Car { Name = "Celta" });
     carList.Add(new Car { Name = "Lamborghini" });
     carList.Add(new Car { Name = "S10" });
     carList.Add(new Car { Name = "New Civic" });
}

2) Adicione os scripts necessários para sua View, serão eles:

jquery-1.4.2.min.js (pode baixá-lo em http://jquery.com/)
jquery.autocomplete.min.js (pode baixá-lo em http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/)

3) Faça o método em javascript para buscar os dados no servidor:

Agora que entrará a técnica de usar o post do jquery, abaixo a função:

<script type="text/javascript">
       function carsAutoComplete(searchValue) {
              if (searchValue != "") {
                     $.post("/AutoComplete/Cars", { search: searchValue }, function (result) {
                              $(".carsAutoComplete").autocomplete(result);
                      });
              }
        }
</script>

O que estou fazendo aqui é o seguinte, o meu valor da consulta virá por parâmetro, se esse valor for diferente de vazio então chamo a ação do meu controller ("/AutoComplete/Cars"), passo o parâmetro a ser pesquisado ({ search : searchValue }) repare no mesmo nome do parâmetro da ação, isso faz com que o Asp.NET MVC atribua o valor automaticamente para a função, e o retorno eu o pego em uma função delegate (function(result) { ...) result será automaticamente meu vetor em javascript, o Json(cars) fará automaticamente isso pra mim, nessa função eu digo que todos os controler que tenham a classe carsAutoComplete ($(".carsAutoComplete")) deverão ser autocomplete e os valores a serem completados serão o resultado da pesquisa.

4) Indique o campo que receberá o autocomplete, juntamente com a ação que chamará o autocomplete, porém o class tem que ter o carsAutoComplete:

<input type="text" class="carsAutoComplete" onkeypress="carsAutoComplete(this.value)" />

Pronto!!! Seu autocomplete está pronto.

Até a próxima.

sexta-feira, 12 de fevereiro de 2010

Asp.NET Two-Way DataBind

Gostaria nesse post de publicar que fiz alguns controles Asp.Net com Two-Way DataBind.
A maneira de usar fica igual ao do Windows Forms, por exemplo:

this.txtName.DataBinds.Add("Text", objeto, "Propriedade");

Para quem estiver interessado, segue o link do codeplex:

Asp.NET Two-Way DataBind Controls

Sugestões são muito importantes para mim.

Obrigado.

segunda-feira, 21 de dezembro de 2009

Chamando função do lado servidor com Javascript

Ja vi em muitos lugares essa dúvida, e vi muitas soluções complicadas, explicações gigantes para resolver esse problema.
Aqui mostro de uma forma mais direta como resolver esse problema de chamar uma função C# por exemplo com Javascript.
Primeiro no código fonte de sua página adicione um método estático com o atributo WebMethod. Seu código ficará assim:

public partial class _Default : System.Web.UI.Page
{
     protected void Page_Load(object sender, EventArgs e)
     {

     }

     [System.Web.Services.WebMethod]
     public static void MeuMetodo()
     {
     }
}

Agora no seu html adicione um ScriptManager colocando EnablePageMethods="true" e logo abaixo dele adicione sua função javascript, ficando assim:

<form if="form1" runat="server">
    <asp:scriptmanager EnablePageMethods="true" runat="server"></asp:scriptmanager>
    <script type="text/javascript">
          function Metodo() {
                PageMethods.MeuMetodo();
          }
    </script>
    <button onclick="javascript:Metodo();">Clique</button>
</form>

Esse pequeno artigo mostra de maneira simples como chamar uma função que está do lado do servidor por Javascript.

Até a próxima.

quinta-feira, 22 de outubro de 2009

Command GridView

Nessa postagem comentarei um dos tópicos mais perguntados, como gerar um comando a partir de um botão que está no GridView e pegar um dado desejado.
Após criar um novo projeto Web Application, adicione um GridView à sua página:




Feito isos clique em Edit Columns, escolha button field e clique em Add, do lado direito procure por CommandName e coloque Click, como na imagem:





Agora crie uma classe como abaixo:

public class Campos
{
      public int Id{get;set;}
      public string Nome{get;set;}
      public string Sobrenome{get;set;}
}

No page_load da página escreva esse código:

protected void Page_Load(object sender, EventArgs e)
{
        List campos = new List();
        campos.Add(new Campos(){Id = 1, Nome = "Murilo", Sobrenome = "Gomes"});
        campos.Add(new Campos(){Id = 2, Nome = "Gabriel", Sbrenome = "Gomes"});

        GridView1.DataSource = campos;
        GridView1.DataBind();

        GridView1.RowCommand += new GridViewCommandEventHandler(GridView1_RowCommand);
}

Quando você rodar o programa o resultado será esse:





Agora vamos ao código para poder pegar o valor do ID, logo abaixo em que termina Page_Load escreva essa função:

void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
{
         if(e.CommandName == "Click")
        {
                 int indice = Convert.ToInt32(e.CommandArgument);
                 int id = Convert.ToInt32(GridView1.Rows[indice].Cells[1].Text);
        }
}

Pronto agora no id você sempre terá o valor do Id da linha em que o botão foi clicado.

Alguns conceitos, o CommandArgument te retorna o indice da linha que gerou o evento.
O e.CommandName retorna o nome do evento, nesse caso estamos querendo o command Click que nós demos o nome acima.

terça-feira, 29 de setembro de 2009

Funcionalidade de classe e membro static

Desde o último mês ando participando com grande frequência dos fóruns da msdn, e faz alguns dias que respondi uma dúvida da classe static. Porém ao responder as perguntas fui respondendo algumas coisas que não havia pensado sobre ela, como ocupação de memória, performance e velocidade.
Estou aqui para mostrar como foi a discussão porém como uma explicação.
O que é um membro static? Um menbro static é um membro de uma classe que terá o mesmo valor em todas as partes do código, por exemplo, considere uma classe

class MinhaClasse
{
public int Valor;
public static int ValorCompartilhado;
}

Qual a diferença entre Valor e ValorComparilhado? É o seguinte se você fizer:

MinhaClasse c = new MinhaClasse();
c.Valor = 2;

O 2 comente será visível para a instância c, agora caso você faça MinhaClasse.ValorCompartilhado = 2 o 2 será visível em todo o programa e em todas as partes que você faça int v = MinhaClasse.ValorCompartilhado a v será atribuido 2.

O que é uma classe static? Uma classe static só poderá conter membros static, assim no exemplo anterior teríamos que mudar int Valor para static int Valor.

Quando usar uma classe ou membro static? Primeiro vou responder a membors static, fica óbvio que se você precisa utilizar uma mesma instancia ou valor em todo o programa, imagine por exemplo uma instancia de uma conexão com o banco, você usará uma instancia dessa conexão como static. E classe? Classe static é muito utilizado para classes que contém apenas métodos ou então àquelas em que você após analisar verá que todos seus membros ficariam melhor como static, pois seus valores são compartilhados em todo o programa.

Discutiremos agora a parte de memória, desempenho e velocidade, para isso vamos levar em consideração estas duas classe:

public static class ClasseStatic
{
private static OutraClasse oc = new OutraClasse();
public static int Calculo = oc.Calcular();
public static string Nome = oc.RetornaNome();
}

public class ClasseNaoStatic
{
private OutraClasse oc = new OutraClasse();
public int Calculo = oc.Calcular();
public string Nome = oc.RetornaNome();
}

O que a OutraClasse faz não nos importa, analisaremos outras coisas.

Memória:
Considerando a classe static nós teremos:
OutraClasse = 1
int = 1
string = 1

Agora considerando a classe não static nós teremos os dados acima a cada nova instancia dela, fazendo então por exemplo:
ClasseNaoStatic ns1 = new ClasseNaoStatic();
ClasseNaoStatic ns2 = new ClasseNaoStatic();
Você terá:
OutraClasse = 2
int = 2
string = 2

Tendo assim um consumo menor de memória para a classe static.

Performance e velocidade:
Como chamamos dois métodos da classe OutraClasse para atribuir a Calculo e Nome e considerando uma velocidade para este método retornar, então teremos um tempo menor para a classe static, e levando a atribuição na pilha de métodos podemos ver uma melhor performance na classe static também.

Por que então não usar sempre static?
Imgine a seguinte situação, uma classe que controla quais usuários estão usando seu sistema, se for static e cada vez que um novo usuário entrar no sistema, você atribuir seu nome por exemplo ao membro static, você perderá os outros pois todo o programa agora usará o novo valor.

Conclusão:
Use static quando você ver a necessidade de seus dados terem o mesmo valor em todo o programa e uma mudança nele afete também todo o programa.

Para ver como foi a discussão no fórum segue o link:
http://social.msdn.microsoft.com/Forums/pt-BR/vscsharppt/thread/95bf6774-0d70-4cec-b1bd-20b9eeb4d030

segunda-feira, 31 de agosto de 2009

Usando javascript para percorrer Repeater

Hoje entrei em uma situação na qual nunca tinha passado, me pediram para fazer uma função em javascript para percorrer os checkbox de um repeater e analisar se pelo menos um estava checado.
O único problema é que o Visual Studio gera código pra você sobrescrevendo o nome e o id que você deu quando se usa usercontrol, assim um name="chkPassenger" se tranformou em: mUsrMain_UsrWebCheckInPassengersByFlight1_rptPNRSegments_ctl00_rptPassengers_ctl02_chkPassenger,
tudo bem ele gerou um span com o name correto, mas eu queria encontrar diretamente o checkbox.
A solução foi escrever este código:

function GetAllCheckBox()
{
var count = 0;
var inputs = document.getElementsByTagName('input');
for(var i = 0; i < inputs.length; i++)
{
      if(inputs[i].type == 'checkbox' && inputs[i].name.indexOf('chkPassenger') != -1)
     {
            if(inputs[i].checked == true)
            {
                   count++;
                   break;
            }
     }
}

if(count == 0)
      return false;
return true;
}

O porque do return? Bem como este evento estava sendo gerado por um itemcommand ele estava dando postback e claro, se eu precisava fazer em javascript era justamente para evitar ele. Para cancelar um postback, adicione a seguinte propriedade no controle que gerará ele:

OnClienteClick="return GetAllCheckBox();"

Assim se retornar false ele cancelará o postback, caso contrário o postback ocorrerá normalmente.

terça-feira, 25 de agosto de 2009

Adicionando imagens no Crystal Report

Uma das coisas mais comuns a se fazer em software, é a possibilidade de fazer um resumo de vendas para que o usuário possa escolher entre salvar em diversos formatos ou então imprimir.
Para que isso seja feito com facilidade, Visual Studio possui além dos modelos de documentos da Microsoft, uma ferramenta poderosa chamada Crystal Report.
Infelizmente o Crystal Report não possui um campo mapeado para imagem, onde você possa adicionar apenas uma url e ele faça todo o trabalho para você. Você pode estar pensando "mas também o que mais ele quer?", porém isso é comum quando se trabalha com a classe Image do .NET.
Para realizar esse trabalho é necessário adicionar um array de bytes.

Em seu datasource crie um atributo byte[] por exemplo:

    public byte[] Image { get; set; }

Feito isso de um refresh no seu datasource no Crystal Report para que você possa visualizar o novo campo, após visualizado apenas arraste o novo campo para o report.

Adicione o namespace: using System.IO;

Agora para ler a imagem de seu disco adicione o seguinte código:

    FileStream stream = new FileStream(url, FileMode.Open, FileAccess.Read);
    BinaryReader reader = new BinaryReader(stream);
    suaClasse.Image = reader.ReadBytes(Convert.ToInt32(stream.Length));
    reader.Close();
    stream.Close();

Vincule o datasource do Crystal Report para uma lista de sua classe ou o seu dataset e então o Crystal Report poderá realizar o trabalho para você.