Aplicação ReadWriteData Aplicação com 1 página, que mostra num controlo DataGrid uma tabela de uma base de dados. O controlo DataGrid permite editar os valores mostrados nas células, e efectuar as correspondentes actualizações na base de dados. O modelo usado para ligação à base de dados é o modelo desligado, através de um DataSet e de um DataAdapter. Para a construção da aplicação usa-se programação visual auxiliada por wizards. A construção do programa segue o “Walkthrough: Using a DataGrid Web Control to Read and Write Data”, existente no Help do Visual Studio.NET. Base de Dados: loja.mdb Tabela mostrada no controlo DataGrid: Produtos Campos da tabela Produtos: IdProd, NomeProd, Preco O DataGrid usa a funcionalidade de paging apresentando apenas 10 linhas em cada página. Possui uma coluna com 2 botões, um para editar a linha (permitindo a edição de todas as células excepto a que contém a chave primária) e outro para apagar a linha (embora como não se deve apagar informação previamente guardada numa base de dados, deveria apenas alterar um campo da linha, fazendo o apagamento lógico e não físico. No entanto, a linha considerada logicamente apagada, não deveria ser mostrada no DataGrid. Para isso a selecção dos registos a mostrar no DataGrid deveria ter uma cláusula WHERE com a condição do campo apagado igual a false). Notas: 1 – Acesso ao ficheiro da base de dados. Como se usa uma base de dados Access é necessário dar acesso ao ficheiro. No explorer, com o botão direito do rato em cima do ficheiro, seleccionar Security. Adicionar o utilizador ASPNET do w2ks com full control. Os computadores existentes nos laboratórios pertencem ao domínio, existindo o utilizador ASPNET. Nos outros computadores (que não pertencem ao domínio), não existe o utlizador ASPNET. Nesses é necessário dar full control aos 2 utilizadores (internet guest account – conta de convidado da internet, e everyone - todos) quer para o ficheiro da base de dados, quer para o directório no qual ele está contido. No windows XP para permitir a utilização de segurança, é necessário seleccionar o menu tools de uma pasta (ou do windows explorer), escolher “Folder Options”, e no separador View (Ver), na lista de Advanced settings (Definições avançadas) retirar a verificação (des-seleccionar o check box) da opção “Use simple file sharing” (Utilizar partilha de ficheiros simples - Recomendado). 2 – Ligação à base de dados efectuada pelo Visual Studio Se se usa o wizard do Visual Studio para a geração da string de conexão, deve procederse do seguinte modo: - para a geração da string de conexão deve-se indicar um caminho para a base de dados acesível da nossa conta, por ex., W:\ReadWriteData\loja.mdb (se for W a letra do drive que mapeia o w2ks); - para a execução da página, quem executa é a conta ASPNET, e para esta conta, o caminho W: não faz sentido (não existe este drive). Portanto temos que mudar manualmente a string de conexão, no código gerado automaticamente pelo wizard, no método InializeComponent, substituindo W:\ReadWriteData\loja.mdb por C:\Inetpub\wwwroot\XXX\loja.mdb, em que XXX é o nome do directório virtual (ex. 900330 para os alunos e moutaw para os docentes). 3 – Caso no acesso à BD surja a excepção Ficheiro já em uso. Verificar se o ficheiro mdb não está aberto pelo Access ou pelo Visual Studio.NET. Para verificar se está aberto pelo Visual Studio.NET fazer View, Server Explorer e verificar as conexões existentes e o respectivo estado. Se alguma conexão estiver ligada, pode-se desligar. Se se pretender ligar, seleccionar Refresh. Esta excepção pode aparecer se noutra função da mesma página, a ligação à base de dados foi aberta mas não fechada. Deve-se corrigir e fechar sempre as ligações à base de dados. 4 – Caso no acesso à BD surja a excepção Impossibilidade de fazer lock. Modificar a string de conexão gerada automaticamete pelo Visual studio, retirando a parte “Mode=Share Denny None” e “DataBase Locking Mode”. Alternativamente substituir toda a string de conexão pela string usada em exercícios anteriores. Construção do programa: 1. Criar a página Formulário Web com os componentes data necessários e o controlo DataGrid para mostrar os dados. 2. Adicionar código para ler os dados da base de dados e ligar os dados ao controlo DataGrid. 3. Configurar o controlo DataGrid para permitir edição dos dados. 4. Adicionar código para actualização dos dados. Funcionamento do programa: Mostrar: Actualizar: Dados na Base de Dados DataSet DataGrid Passo 1: Criar componentes data e o controlo DataGrid Divide-se em 2 acções: - Criar o data adapter. O data adapter contém instruções SQL para ler e escrever informação para a base de dados. - Gerar o esquema do dataset definindo as tabelas e colunas constituintes. O Visual Studio criará uma classe dataset e adicionará uma instância ao formulário. Procedimentos: A. Criar os objectos Connection e DataAdapter - Criar um novo Projecto designado ReadWriteData - Incluir a base de dados no Projecto: Add > Add Existing Item loja.mdb - Alterar permissões de acesso à base de dados ... (Ver as Notas descritas atrás) - Criar o objecto DataAdapter: Toolbox > tabulador Data > arrastar OleDbDataAdapter Surge o wizard. Permite especificar o objecto Connection e os Comandos a executar na base de dados que o DataAdapter irá usar. Next > New Connection Fornecedor: Microsoft Jet 4.0 OLE DB Provider Seguinte 1. Nome da base de dados ... Procurar loja.mdb debaixo de ReadWriteData 2. Nome do utilizador Admin 3. Testar a Ligação OK Mudar manualmente a string de conexão ... (Ver as Notas descritas atrás) Next Use SQL Statements Next What data should the data adapter load into the dataset? Select * From Produtos ou através do Query Builder Don´t include password The data adapter oleDbDataAdapter was configured successfuly. Generated SELECT, INSERT, UPDATE e DELETE Statements. Generated table mappings. Finish Surgem no Page 2 objectos: oleDbDataAdapter e oleDbDataConnection B. Criar o DataSet Visual Studio vai gerar o dataset automaticamente baseado na instrução Select especificada no data adapter. Primeiro cria uma classe DataSet (ficheiro .xsd) que descreve os elementos do dataset (tabelas, colunas e restrições) e em seguida cria uma instância. Procedimentos: Botão direito do rato no oleDbDataAdapter Seleccionar Generate DataSet New: DataSet1 (nome da classe criada) Choose which table to add to the dataset Ok Clicar Show All Files: ficam visíveis os ficheiros DataSet1.xsd e DataSet1.cs com as definições do schema e da classe que definem o dataset. Visual Studio adiciona uma instãncia da classe DataSet1 – DataSet11 – à página. C. Criar o DataGrid Toolbox > Web Forms > arrastar DataGrid AutoFormat: Professional1 Property Builder: (General) DataSource: DataSet11 – nome do dataset para ligar ao datagrid DataMember: Produtos – nome da tabela do dataset para ser visualizada Data Key Field: IdProd - chave primária para os registos da tab. Produtos. Ok. O controlo DataGrid já está ligado ao dataset, mas o dataset não é carregado automaticamente. Passo 2: Adicionar código para ligar os dados ao controlo DataGrid. No método Page_Load colocar: private void Page_Load(object sender, System.EventArgs e) { // Put user code to initialize the page here oleDbDataAdapter1.Fill(dataSet11); if (!Page.IsPostBack ) DataGrid1.DataBind(); } Passo 3: Configurar o controlo DataGrid para permitir edição dos dados. Para permitir editar linhas do datagrid adicionar um botão Edit a cada linha da grelha. A activação do botão alterará os componentes da linha, passando os campos editáveis para text boxes, e o botão Edit será substituído por 2 botões Update e Cancel. Procedimentos: Property Builder Columns Available Columns + Button Column Seleccionar Edit, Update e Cancel Button type = Push Button (Link Button) Adicionar ( > ) para adicionar os botões à caixa de colunas seleccionadas. Ok. Criação do código de tratamento de eventos para colocar linhas no modo de edição O controlo DataGrid possui a capacidade de colocar linhas no modo de edição através da propriedade EditItemIndex. Para colocar uma linha em modo de edição coloca-se o valor da propriedade com o índice dessa linha (as linhas começam por zero), e para voltar ao modo normal coloca-se o valor da propriedade a -1. Exemplo: Colocar a terceira linha do DataGrid1 em modo de edição: DataGrid1.EditItemIndex = 2; Colocar o DataGrid1 em modo normal de visualizção: DataGrid1.EditItemIndex = -1; Procedimentos: Propriedades do controlo DataGrid1 Seleccionar o botão Events Duplo clique em EditCommand Duplo clique em CancelCommand Duplo clique em UpdateCommand Colocar o seguinte código: No tratamento de eventos EditCommand private void DataGrid1_EditCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e) { DataGrid1.EditItemIndex = e.Item.ItemIndex; DataGrid1.DataBind(); } No tratamento de eventos CancelCommand private void DataGrid1_CancelCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e) { DataGrid1.EditItemIndex = -1; DataGrid1.DataBind(); } Testar a parte da aplicação já construída. O controlo DataGrid deve mostrar os dados do dataset, o qual contém dados extraídos da base de dados. Testar a capacidade de edição de linhas. Passo 4: Adicionar código para actualização dos dados na base de dados O botão Update deve desencadear as seguintes acções. 1. Determinar que linha do controlo DataGrid foi actualizada. Obter o valor da chave dessa linha. 2. Ler os valores mudados da linha actualizada. 3. Encontrar a linha do dataset com o mesmo valor da chave e escrever as mudanças para essa linha. Está actualizado o dataset mas ainda não está actualizada a base de dados. 4. Executar o comando SQL que envia as mudanças do dataset para a base de dados. 5. Refrescar o conteúdo do controlo DataGrid (com os dados do dataset). Ponto 1. Quando o botão é activado, o objecto evento passado como argumento tem uma propriedade Item que é o objecto que representa a linha do controlo DataGrid. Este objecto Item tem uma propriedade ItemIndex com o índice da linha. O controlo DataGrid tem uma propriedade DataKeys com a colecção de chaves da tabela. Através do índice da linha determina-se a chave dessa linha. string key = DataGrid1.DataKeys[e.Item.ItemIndex].ToString(); Ponto 2. A propriedade Item do objecto evento (que representa a linha) tem uma propriedade Cells, com a colecção de células dessa linha. Cada célula tem uma propriedade Controls, com os controlos de cada célula (muitas vezes existe apenas 1 controlo em cada célula -- Controls[0] – mas uma célula pode conter mais que um controlo). Código para obter os valores dos controlos editáveis das células da linha: TextBox Tb = (TextBox)(e.Item.Cells[1].Controls[0]); string NomeProduto = Tb.Text; Tb = (TextBox)(e.Item.Cells[2].Controls[0]); string PrecoProduto = Tb.Text; Ponto 3. Encontra a linha da tabela do dataset correspondente à linha que o utilizador actualizou no datagrid. O método FindBy<nome_do_campo_chave> invocado com o valor da chave como argumento, retorna uma referência para a linha. DataSet1.ProdutosRow r = dataSet11.Produtos.FindByIdProd(int.Parse(key)); Escreve as mudanças actualizando a tabela do dataset. r.NomeProd = NomeProduto; r.Preco = int.Parse(PrecoProduto); Notas: Se a tabela Produtos da base de dados loja.mdb não tem apenas uma chave IdProd, mas possui duas chaves IdProd e IdCat, o método FindByIdProd não existe (existirá o método FindByIdProdIdCat(-,-). Alternativas: - Ao criar o DataAdapter na instrução Select não incluir todos os campos da tabela Produtos (excluir o campo IdCat). Deste modo o dataset já não contém o campo IdCat. Ou - Alterar na base de dados a tabela Produtos de modo a ter uma única chave IdProd. Depois apagar o dataset e gerar um novo dataset a partir da base de dados (ou mantendo o dataset já gerado, alterar o schema apagando as chaves e criando apenas uma). Ponto 4. Executa o comando SQL que envia as mudanças do dataset para a base de dados. oleDbDataAdapter1.Update(dataSet11); Termina o modo de edição do DataGrid. DataGrid1.EditItemIndex = -1; Ponto 5. Refrescar o conteúdo do controlo DataGrid (com os dados do dataset). DataGrid1.DataBind(); Em seguida mostra-se o código completo a incluir no método de tratamento de eventos UpdateCommand: private void DataGrid1_UpdateCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e) { // Obtem os valores do campo chave da linha actualizada string key = DataGrid1.DataKeys[e.Item.ItemIndex].ToString(); // // // // // // // // Obtem os valores dos controlos (textboxes) que o utiliz. actual. As colunas do DataGrid são expostas na colecção Cells. Cada célula tem uma colecção de controlos. Neste caso, só há um controlo em cada célula – um TextBox. Ler o valor do TextBox através da propriedade Text para uma variável local (é necessário casting). A 1.ª coluna -- Cells(0) – contém os botões Update e Cancel. // Obtem o valor do controlo TextBox control na 2.ª coluna TextBox Tb = (TextBox)(e.Item.Cells[1].Controls[0]); string NomeProduto = Tb.Text; // Obtem o valor do controlo TextBox control na 3.ª coluna Tb = (TextBox)(e.Item.Cells[2].Controls[0]); string PrecoProduto = Tb.Text; // // // // Encontra a linha da tabela do dataset correspondente à linha que o utilizador actualizou no datagrid. O método FindBy<nome_do_campo_chave> invocado com o valor da chave como argumento, retorna uma referência para a linha. DataSet1.ProdutosRow r = dataSet11.Produtos.FindByIdProd(int.Parse(key)); // Actualiza a tabela do dataset. r.NomeProd = NomeProduto; r.Preco = int.Parse(PrecoProduto); // Executa a instrução SQL para actualizar a bd a partir do dataset oleDbDataAdapter1.Update(dataSet11); // Termina o modo de edição do DataGrid DataGrid1.EditItemIndex = -1; // Refresca o DataGrid DataGrid1.DataBind(); } Testar a aplicação. Vamos fazer ainda as seguintes alterações: 1. 2. 3. 4. Retirar a coluna IdCat; Adicionar nova coluna de botões Delete; Colocar o campo ProdId não editável, porque é a chave da tabela; Configurar o controlo datagrid para efectuar paginação. Pontos 1 e 2: O controlo DataGrid permite escolher as colunas específicas a serem mostradas, mudar a posição relativa, mudar os cabeçalhos, etc. Para retirar a coluna IdCat e adicionar uma nova coluna com botões seleccionar o controlo DataGrid1: Property Builder (surge a janela DataGrid1 Properties) Separador Columns Retirar a selecção em “Create columns automatically at run time” Na área Selected Columns já existe a coluna Edit, Update e Cancel. Em Available Columns seleccionar: - a coluna IdProd e adicionar (>) à área Selected Columns. - a coluna NomeProd e adicionar (>) à área Selected Columns. - a coluna Preco e adicionar (>) à área Selected Columns. Expandir Button Column e seleccionar Edit e adicionar (>) à área Selected Columns. Na área Selected Columns seleccionar Delete e premir o botao à direita com a seta ascendente para posicionar a coluna Delete em 2.º lugar. Deste modo determinámos os posicionamentos relativos das colunas. Ponto 3. Na área Selected Columns seleccionar a coluna IdProd e colocar um visto no checkbox Read-only. Deste modo ao colocar a linha no modo editável este campo permanece não editável. Ponto 4. Para configurar o controlo Datagrid para mostrar uma página de cada vez: Seleccionar o controlo DataGrid1: Property Builder (surge a janela DataGrid1 Properties) Separador Paging Seleccionar o check box Allow paging Colocar o tamanho da página (Page size) Seleccionar o check box Show navigation buttons e definir a posição e modo para os botões de navegação. Clicar Apply e depois OK. Para que na página “code-behind” surja o método de tratamento de eventos PageIndexChanged, seleccione o botão Events nas Propriedades do controlo DataGrid1, e faça duplo clique em PageIndexChanged. Coloque o seguinte código no método criado: private void DataGrid1_PageIndexChanged(object source, System.Web.UI.WebControls.DataGridPageChangedEventArgs e) { DataGrid1.CurrentPageIndex = e.NewPageIndex; DataGrid1.DataBind(); } Finalmente grave as mudanças, construa o projecto (Build Project) porque foi adicionado código, e veja a página no browser (View in browser) para testar a funcionalidade de paginação.