18 11 2015
Multi-relatórios no mesmo formulário com o Report Viewer
Um erro comum que muitas pessoas cometem ao trabalhar com o Report Viewer no Windows Forms é criar um formulário (do Windows Forms) para cada relatório do sistema. Eu diria que o próprio designer do Report Viewer no Visual Studio induz os desenvolvedores a esse erro, uma vez que ele possibilita a escolha do relatório na smart tag do controle. No artigo de hoje, eu vou te mostrar como exibir múltiplos relatórios no mesmo formulário com o Report Viewer.
Criar um formulário para cada relatório não é a melhor maneira de se trabalhar. Imagine que você tenha 15 relatórios no seu sistema. Trabalhando dessa forma, você teria 15 formulários só para fazer a exibição de relatórios. Já pensou se você quiser alterar alguma propriedade do controle do Report Viewer no sistema todo? Por exemplo, digamos que você queira desabilitar o botão de exportação do Report Viewer. Você teria que alterar cada um dos 15 formulários. Nada prático, não é mesmo?
Criando dois relatórios de exemplo
Para exemplificar essa problemática, vamos criar um novo projeto do tipo “Windows Forms Application“. Dentro desse novo projeto, adicione dois DataSets tipados: um chamado “DataSetCliente” e outro chamado “DataSetFornecedor“. No DataSetCliente, adicione uma DataTable chamada “Cliente” e, no DataSetFornecedor, adicione uma DataTable chamada “Fornecedor“:
Feito isso, adicione dois novos relatórios ao projeto: um relatório chamado “ReportCliente” e outro chamado “ReportFornecedor“. Ajuste o layout dos relatórios para que eles fiquem parecidos com as imagens abaixo:
Como você pode perceber, o layout desses relatórios é extremamente simples: um título no cabeçalho do relatório e uma “Table” na área de detalhes listando as informações dos DataSets que criamos anteriormente.
O jeito “errado” – um formulário para cada relatório
Agora que já temos os DataSets e relatórios preparados, precisamos exibi-los de alguma forma. A maneira mais fácil de fazermos isso é criarmos um formulário para cada um desses relatórios. Para fazermos isso, temos que adicionar dois novos formulários ao nosso projeto, arrastarmos um controle do Report Viewer em cada um deles e, finalmente, temos que escolher o relatório desejado utilizando a smart tag do controle:
Em seguida, temos que carregar os dados do DataSet dentro do construtor de cada formulário:
public FormReportCliente() { InitializeComponent(); DataSetCliente.Cliente.AddClienteRow("Cliente 1"); DataSetCliente.Cliente.AddClienteRow("Cliente 2"); DataSetCliente.Cliente.AddClienteRow("Cliente 3"); }
public FormReportFornecedor() { InitializeComponent(); DataSetFornecedor.Fornecedor.AddFornecedorRow("Fornecedor 1"); DataSetFornecedor.Fornecedor.AddFornecedorRow("Fornecedor 2"); DataSetFornecedor.Fornecedor.AddFornecedorRow("Fornecedor 3"); DataSetFornecedor.Fornecedor.AddFornecedorRow("Fornecedor 4"); }
Finalmente, crie um novo formulário (ou altere o “Form1” que é criado automaticamente pelo Visual Studio) que servirá como menu para chamar um relatório ou outro:
private void clientesButton_Click(object sender, EventArgs e) { var reportCliente = new FormReportCliente(); reportCliente.Show(); } private void fornecedoresButton_Click(object sender, EventArgs e) { var reportFornecedor = new FormReportFornecedor(); reportFornecedor.Show(); }
E com isso conseguimos exibir os dois relatórios sem problema algum. O real problema surge quando quisermos customizar alguma coisa no formulário de exibição dos relatórios no nosso aplicativo. Para isso teríamos que fazer a mesma alteração em cada um dos formulários de exibição de relatórios. Quando só temos dois relatórios até que não é difícil, mas, quanto mais relatórios tivermos no nosso projeto, mais difícil fica a manutenção ao utilizarmos essa sistemática.
A alternativa – um único formulário para todos os relatórios
Após termos conferido o jeito “errado” de exibirmos múltiplos relatórios com o Report Viewer, que tal conferirmos uma alternativa com um custo de manutenção muito mais baixo? A alternativa é criarmos um único formulário que será utilizado para fazermos a exibição de todos os relatórios do nosso sistema. Esse formulário receberá por parâmetro todas as informações necessárias para carregar o relatório e exibi-lo.
Para isso, adicione um novo formulário no projeto, chamado “FormRelatorio“. Esse formulário deverá ter um controle do Report Viewer, porém, não escolheremos nenhum relatório no designer (faremos isso no code-behind utilizando os parâmetros recebidos).
Feito isso, vá para o code-behind do formulário e altere a visibilidade do construtor para “private“. Isso porque criaremos um novo método público e estático no formulário que será encarregado de criar e exibir uma nova instância de “FormRelatorio” (isso facilita a chamada para a exibição de um novo relatório – não se preocupe, você entenderá melhor o motivo daqui a pouco). Além disso, vamos adicionar alguns parâmetros no construtor: “path“, “isEmbeddedResource“, “dataSources” e “reportParameters“:
private FormRelatorio(string path, bool isEmbeddedResource, Dictionary<string, object> dataSources, Dictionary<string, object> reportParameters = null) { InitializeComponent(); }
O parâmetro “path” conterá o caminho para o relatório, que pode ser um arquivo em disco ou um “embedded resource” da aplicação (quando o relatório é adicionado dentro do próprio projeto, como estamos fazendo no exemplo deste artigo). É justamente por esse motivo que precisamos do segundo parâmetro (“isEmbeddedResource“), no qual indicaremos se o “path” corresponde a um caminho em disco ou um caminho para um “embedded resource” do projeto.
Em seguida, temos os parâmetros “dataSources” e “reportParameters“, que são dois dicionários com chave string e valor object. Eles são utilizados para popular as fontes de dados do relatório e os parâmetros necessários para o relatório. Note que “reportParameters” é opcional, uma vez que a maioria dos relatórios não utilizam parâmetros.
E como é que implementamos a lógica para cada um desses parâmetros? Confira no código abaixo:
private FormRelatorio(string path, bool isEmbeddedResource, Dictionary<string, object> dataSources, Dictionary<string, object> reportParameters = null) { InitializeComponent(); // path + isEmbeddedResource. if (isEmbeddedResource) this.reportViewer.LocalReport.ReportEmbeddedResource = path; else this.reportViewer.LocalReport.ReportPath = path; // dataSources. foreach (var dataSource in dataSources) { var reportDataSource = new Microsoft.Reporting.WinForms.ReportDataSource(dataSource.Key, dataSource.Value); this.reportViewer.LocalReport.DataSources.Add(reportDataSource); } // reportParameters. if (reportParameters != null) { var reportParameterCollection = new List<Microsoft.Reporting.WinForms.ReportParameter>(); foreach (var parameter in reportParameters) { var reportParameter = new Microsoft.Reporting.WinForms.ReportParameter(parameter.Key, parameter.Value.ToString()); reportParameterCollection.Add(reportParameter); } this.reportViewer.LocalReport.SetParameters(reportParameterCollection); } }
Simples, não? Nós basicamente utilizamos os parâmetros do construtor para configurar o nosso controle do Report Viewer. É justamente isso que é feito no “background” pelo Visual Studio quando você seleciona um relatório específico no designer do Report Viewer.
Agora que já temos o construtor com os parâmetros e a sua implementação, vamos criar aquele método estático que será responsável pela criação e exibição do “FormRelatorio“. Para isso, dentro do “FormRelatorio“, adicione o seguinte método:
public static void ShowReport(string path, bool isEmbeddedResource, Dictionary<string, object> dataSources, Dictionary<string, object> reportParameters = null) { var formRelatorio = new FormRelatorio(path, isEmbeddedResource, dataSources, reportParameters); formRelatorio.Show(); }
Finalmente, podemos voltar ao nosso formulário de menu para alterá-lo de forma que ele utilize o nosso “FormRelatorio“. Veja só como fica o código alterado:
private void clientesButton_Click(object sender, EventArgs e) { //var reportCliente = new FormReportCliente(); //reportCliente.Show(); DataSetCliente dsClientes = new DataSetCliente(); dsClientes.Cliente.AddClienteRow("Cliente 1"); dsClientes.Cliente.AddClienteRow("Cliente 2"); dsClientes.Cliente.AddClienteRow("Cliente 3"); FormRelatorio.ShowReport( "MultiRelatorios.ReportCliente.rdlc", true, new Dictionary<string, object>() { { "DataSetCliente", dsClientes.Cliente } }); } private void fornecedoresButton_Click(object sender, EventArgs e) { //var reportFornecedor = new FormReportFornecedor(); //reportFornecedor.Show(); DataSetFornecedor dsFornecedores = new DataSetFornecedor(); dsFornecedores.Fornecedor.AddFornecedorRow("Fornecedor 1"); dsFornecedores.Fornecedor.AddFornecedorRow("Fornecedor 2"); dsFornecedores.Fornecedor.AddFornecedorRow("Fornecedor 3"); dsFornecedores.Fornecedor.AddFornecedorRow("Fornecedor 4"); FormRelatorio.ShowReport( "MultiRelatorios.ReportFornecedor.rdlc", true, new Dictionary<string, object>() { { "DataSetFornecedor", dsFornecedores.Fornecedor } }); }
Muito mais organizado, não é mesmo? Com isso, ao invés de ficar criando um formulário para cada novo relatório, podemos simplesmente utilizar e evoluir o nosso “FormRelatorio“.
Concluindo
Neste artigo você aprendeu que não é uma boa prática criar um formulário para cada relatório da nossa aplicação. Ao invés disso, é melhor criarmos um formulário único que será utilizado para exibir todo e qualquer relatório disponível no nosso sistema.
Agora, conte para mim nos comentários: você já utiliza hoje em dia um formulário padrão para exibir todos os relatórios? Ou você não sabia desse detalhe e estava criando um formulário para cada relatório do seu sistema? Se a sua resposta for a segunda opção, ajuste o seu projeto agora mesmo para que ele tenha somente um formulário de exibição de relatórios, antes que a situação saia do controle!
Por fim, convido você a inscrever-se na minha newsletter. Ao fazer isso, você receberá um e-mail toda semana sobre o artigo publicado e ficará sabendo também em primeira mão sobre o artigo da próxima semana, além de receber dicas “bônus” que eu só compartilho por e-mail. Inscreva-se utilizando o formulário logo abaixo.
Até a próxima!
André Lima
Image by Pixabay used under Creative Commons
https://pixabay.com/en/tax-forms-income-business-468440/
Cadê o Report Viewer no Visual Studio 2015? Trabalhando com arquivos PDF no C#
Olá André!
Bom primeiramente te Agradeço pela dica. Porém estou com um problema na impressão do relatório, quando eu clico em imprimir no barra superior, a janela de impressão e sim uma massagem com o seguinte conteúdo: erro durante a impressão.
segue imagem do erro:
https://www.dropbox.com/s/vcjrvcw5gol76tz/erro.png?dl=0
Bom vc teria alguma ideia do que por que está aparecendo essa mensagem?
Agradeço pela atenção..
a janela de impressão não aparece, e sim ***
** corrigindo o erro :D
Já achei o erro André:)
Vlw
Olá Wesley!
Que bom que você conseguiu solucionar o erro.. Agora, fiquei curioso.. Você poderia compartilhar aqui qual era realmente o problema e o que você fez para resolvê-lo?
Valeu! Abraço!
André Lima
Boa tarde!
Estou utilizando o ReportViewer em conexão com o banco de dados MySQL, neste caso como eu adiciono as colunas? No seu exemplo você utiliza a string diretamente na coluna:
dsClientes.Cliente.AddClienteRow(“Cliente 1”);
Porém eu preciso puxar estas informações do Select no banco de dados
Agradeço desde já
Olá Rodrigo!
Nesse caso você precisa de um TableAdapter para pegar os dados do banco e jogar dentro da uma DataTable.. Provavelmente você está utilizando o provider ADO NET do MySQL no seu projeto, certo? (se não estiver, confira o meu artigo sobre esse tema).. Dê uma olhada neste artigo do CodeProject sobre MySQL com C#, principalmente na parte onde o autor faz o método “GetAllItems”:
Connecting to MySQL Database using C# and .NET
É basicamente isso que você tem que fazer.. Aí você passa a DataTable para o formulário..
Tenta aí e me avisa depois se você conseguiu.. Caso você não tenha entendido, é só me falar qual parte que você não entendeu que eu tento explicar de outra maneira..
Abraço!
André Lima
Boa noite André, continuo sem conseguir completar o relatório…
Quando eu executo ele abre o desing do relatório, porém os dados vem vazios.
Olá Rodrigo!
Quais foram exatamente as alterações que você fez no seu projeto? Você deu uma olhada naqueles links que eu passei no comentário anterior? Em qual parte você encontrou dificuldade?
Se quiser colocar o seu projeto no Dropbox ou OneDrive para eu dar uma olhada, fique a vontade..
Abraço!
André Lima
Olá Andre, Primeiramente parabenizo pela publicação, me ajudou muito, tenho uma dúvida utilizo Crystal reports 2013, e preciso exibir vários relatórios em uma página aspx, sem conhecer a quantidade prévia que desejo imprimir, serão varios relatórios diferentes, tem uma ideia de como eu poderia fazer isso ?
Olá Lordelo, obrigado pelo comentário!
Como você vai escolher o relatório que será exibido? Você terá tipo um DropDown onde o usuário pode escolher o relatório a ser exibido?
Num sistema desktop que temos aqui, fizemos algo parecido.. No nosso caso, a gente criou um formulário padrão que é utilizado para exibir todos os relatórios do sistema.. No construtor do formulário a gente recebe o caminho do relatório e a fonte de dados.. Ficou mais ou menos assim:
Acho que você poderia fazer algo parecido no web forms, não? Se isso não atende, me explica melhor que eu tento ajudar de uma outra maneira..
Abraço!
André Lima
Muito Obrigado pela resposta!
Funciona assim tenho um sistema web, estou utilizando c# no back-end e web forms no front-end, tenho uma grid com um botao para gerar a impressão a partir de um registro da GRID so que esta funcionalidade necessita imprimir relatórios em série, de forma que não se tem um conhecimento prévio da quantidade a ser impressa e atualmente cada relatório exibido pelo sistema é renderizado em determinada página aspx. mais uma vez obrigado!
Olá Lordelo!
OK, está melhorando, mas, ainda não consegui entender 100%.. Vamos lá.. Você tem um grid com as informações do registro a ser impresso.. O usuário escolhe esse registro e escolhe “imprimir”, certo? Nesse ponto um ou mais relatórios devem ser gerados com base naquele registro, é isso? Em algum lugar você deve ter definido quais relatórios devem ser impressos, não? Se essa informação não está disponível em nenhum lugar da aplicação, quem é que define quais relatórios e quais quantidades de cópias que serão impressas?
Ou o que você quer é gerar mais de um relatório dentro do mesmo “viewer”? Se for isso que você está querendo, que eu saiba, não é possível.. Não dá para configurar mais de um “Document” para o mesmo controle ao mesmo tempo.. Uma alternativa nesse caso seria gerar os PDFs dos “N” relatórios, juntar tudo em um único PDF e exibir para o usuário..
Desculpe as perguntas, mas, eu realmente não consegui entender completamente o que você está querendo fazer.. Se quiser me enviar uns screenshots do sistema com mais explicações, fique à vontade.. Meu e-mail é: contato [arroba] andrealveslima [ponto] com [ponto] br..
Abraço!
André Lima
Olá Andre,
Eu uso Enity Framework, seria a mesma forma de gerar os relatórios como explicado neste artigo?
Olá Elessandro, obrigado pelo comentário!
No caso do Entity Framework você poderia seguir a mesma metodologia.. Só que ao invés de passar um DataSet para o formulário, você passaria o IEnumerable com os dados do relatório..
Abraço!
André Lima
André, obrigado pelo retorno!
Minha consulta está retornando os dados, só que quando enviou para o relatório o mesmo fica em branco.
public partial class FormRelatorioCliente : Form
{
private ClienteBLL clienteBLL = new ClienteBLL();
private int idEmpresaSelecionado = FormPrincipal.idEmpresaSelecionada;
public FormRelatorioCliente()
{
InitializeComponent();
}
private void btnGerarRelatorio_Click(object sender, EventArgs e)
{
var dadosRelatorio = from r in clienteBLL.ClienteRelatorio(“A”, “CPF”, idEmpresaSelecionado)
select new Report.ClienteRelatorio()
{
Cliente_Id = r.Cliente_Id,
ClienteNome = r.ClienteNome,
ClienteCpfCnpj = r.CpfCnpj,
ClienteEndereco = r.Endereco + “, ” + r.EnderecoNumero,
ClienteEnderecoBairro = r.Bairro,
ClienteStatus = r.SituacaoCliente
};
FormRelatorio.ShowReport(“SIGPRO.Desktop.Report.RelatorioCliente.rdlc”, true,
new Dictionary() { { “dsDadosRelatorio”, dadosRelatorio } });
}
}
Eu usei como exemplo o seu artigo “Gerando relatórios do Report Viewer com Entity Framework”
Se puder me ajudar agradeço…
Olá Elessandro!
Estranho hein.. Você tem certeza absoluta que os dados estão sendo retornados na consulta LINQ? Os nomes dos campos da consulta LINQ estão batendo exatamente com os nomes dos campos do DataSet do relatório (inclusive letras maiúsculas e minúsculas)? E o nome do DataSet, também está batendo? O relatório fica em branco ou você recebe um erro falando que o DataSet não foi informado?
Uma coisa que eu tentaria é, ao invés de passar direto o resultado da consulta para a janela, chame um “ToList” antes:
Abraço!
André Lima
Olá André!
O relatório fica em branco.
A consulta está correta;
Conferi os nomes dos campos do DataSet do Relatório varias vezes.
Se você tiver mais alguma dica do que eu posso fazer agradeço.
Abraço, Bom final de semana.
Elessandro Poças
Olá Elessandro!
Que estranho! Você tentou o esquema de chamar o ToList antes de passar os dados pro relatório? Será que você poderia me mandar o seu arquivo rdlc para eu dar uma olhada? Se puder, me envia por e-mail: contato [arroba] andrealveslima [ponto] com [ponto] br..
Abraço e um ótimo final de semana aí pra você também!
André Lima
Olá André,
Funcionou agora! O problema era que no form onde tem o viewer do relatório não tinha o evento load que é criado no momento que você adiciona o componente Report Viewer.
private void FormRelatorioBasico_Load(object sender, EventArgs e)
{
this.rvRelatorioBasico.RefreshReport();
}
Por isso que não mostrava as informações.
Mas agora ficou show do jeito que eu queria. (Windows Form + MySQL + Entity Framework)
Obrigado pela sua atenção….
Olá Elessandro!
Ah tá.. Estava faltando o Refresh.. É, o Report Viewer realmente precisa do Refresh para carregar e exibir os dados do DataSource, senão fica tudo em branco mesmo..
Enfim, fico feliz que você conseguiu resolver o seu problema! Qualquer coisa, é só entrar em contato novamente..
Abraço!
André Lima
Boa tarde, está com uma dúvida de como passar consulta feita em tableadapter para o reportview dessa maneira que você ensinou.
FormRelatorio.ShowReport(“Est_Rel_Analista_Reaproveitamento.rdlc”, true, New Dictionary(Of String, Object)() From {{“Dados_Esteira_Reaproveitamentos”, Me.Dados_Esteira_Reaproveitamentos.BD_Esteira}})
Olá Felipe!
Você precisaria passar a DataTable preenchida pelo DataAdapter, que é aparentemente o que você já está fazendo.. Qual é o erro que você está recebendo?
Abraço!
André Lima
Tenho lido os teus posts e tem me ajudado muito.
Chamo-me Deodact Faustino, tenho a seguinte questão: Gostaria de criar um relatório com reportviewer sem o dataset tipado e mudar o caminho do dataset para o mesmo caminho do banco de dados
Olá Deodact, obrigado pelo comentário!
Você já chegou a dar uma olhada no meu último artigo? Veja se te ajuda:
Passando um DataSet não tipado para o Report Viewer
Abraço!
André Lima
André, bom dia!
Estou com dificuldade sobre Form.
Tenho um Projeto de um Site onde cada página, consigo gerar um Report simples, com alguns dados do Cadastro.
Agora estou com um Cadastro onde tenho que gerar um Form com vários Reports, ou seja, eu tenho que gerar um Documento, tipo no Word, com várias informações em várias páginas.
Os DataSet, os Reports já estão criados, mas não estou conseguindo juntá-los para gerar esse Documento. No Projeto já existente, não consigo adicionar um Windows Form.
Então, eu criei um novo Projeto Windows Form, coloquei os DataSet e os Reports nesse novo Projeto e agora preciso chamá-lo do Projeto já existente. Estou tentando dessa forma:
ReportControl.fillReport(new ReportDataSource { Name = “DataSetDocumentoComercial”, Value = listDocumento }, “~/C:/Users/thais.nogueira/Source/Repos/QUALIVIEW/SGQ.Report/Form1.cs”);
e me aparece o seguinte erro:
“Ocorreu um erro durante o processamento de relatórios local.
A definição do relatório ‘C:\Users\thais.nogueira\Source\Repos\QUALIVIEW\SGQ.Report\Form1.cs’ é inválida.
A definição deste relatório é inválida ou não tem suporte nesta versão do Reporting Services. A definição do relatório pode ter sido criada com uma versão mais recente do Reporting Services, ou inclui conteúdo malformado ou inválido baseado em esquemas do Reporting Services. Detalhes: Dados no nível raiz inválidos. Linha 1, posição 1.”
Desculpe o tamanho do post, mas que estou agarrada neste problema há um tempo e estou precisando de ajuda.
Obrigada desde já.
Olá Thaís!
Pelo que eu entendi, você está com um projeto web e você precisa resolver essa necessidade diretamente no projeto web, certo? Se for esse o caso, não faz sentido você utilizar esse tutorial, uma vez que ele é voltado para aplicações desktop e essa implementação não vai “conversar bem” com o seu projeto web..
Nesse caso eu recomendaria que você desse uma olhada neste outro artigo que eu escrevi uns tempos atrás:
Juntando dois relatórios do Report Viewer em um só
A ideia seria criar um relatório “mestre” que faria a exibição dos N relatórios detalhe via sub-relatório.. Outra opção seria gerar o PDF de todos os relatórios e depois juntar os PDFs em um arquivo só.. Se você decidir seguir por esse caminho, acho que estes meus outros artigos te ajudarão nesse processo:
Como podemos exportar relatórios do Report Viewer?
Trabalhando com arquivos PDF no C#
Abraço!
André Lima
Olá André! Agora que vi sua resposta.
Vou ler seus artigos e tentar!
Muito Obrigada!
OK Thaís, magina.. Qualquer dúvida é só entrar em contato novamente..
Abraço!
André Lima
Boa tarde!
Consegui resolver esse primeiro problema.
Agora estou com outro, o Form está vindo vazio e após um tempo ele desaparece.
Muito bom André, seus tutoriais tem ajudado a mim e a muita gente. Estou a procura dessa solução há algumas semanas, quando finalmente a encontro, está em C#, uso VB.NET!! A conversão trouxe erros que não consegui resolver. Estaca zero novamente.
Olá Moura, muito obrigado pelo comentário!
A conversão para o VB.NET é bem tranquila.. Você pode fazer através do conversor da Telerik, por exemplo..
Converti aqui rapidinho e o código ficou assim (não testei, mas compilou):
E o clique do botão:
Abraço!
André Lima
Bom dia
André
Grande Dica mesmo
Gostarias de Saber se tem um exemplo para VB.NET (OU) Project de demonstração.
Olá Lério, muito obrigado!
Um outro leitor do site já fez essa pergunta mais acima e eu postei a conversão em VB.NET.. Dá uma olhada aqui..
Abraço!
André Lima
[…] para exibirmos os dados desse relatório, vamos utilizar o formulário que eu criei no meu artigo onde eu mostro como carregar múltiplos relatórios do Report Viewer com o mesmo formulário. Uma vez adicionado esse formulário no projeto, veja como fica fácil o código para montarmos uma […]
Bom dia André!
Você tem esse código em Visual basic?
Perdão, já encontrei no site.
Legal, Edson.. Qualquer coisa é só entrar em contato..
Abraço!
André Lima
Olá André, tudo bem?
Parabéns pelo material de excelente qualidade! Sua didática tem ajudado muito!
Nesta matéria você menciona o envio opcional de parâmetros “reportParameters”. Como seria o envio de parâmetros para compor por exemplo o cabeçalho do relatório com os dados da empresa vindos de um datatable?
Grato,
Ednilson do Valle
Olá Ednilson!
A fonte de dados você envia pelo DataSource (parâmetro “dataSources”), justamente como eu faço no artigo, onde eu mando a DataTable “Cliente” ou “Fornecedor”, dependendo do relatório que eu estou mostrando..
Abraço!
André Lima