Archive for the '.NET' Category
Registrar javascripts dinâmicos em páginas ASP.NET nunca foi algo muito prazerozo, mas alguns métodos oferecidos pela Engine como o Page.RegisterClientScriptBlock, que “cospe” um bloco de scripts dentro de uma página.
Isso resolvia alguns casos simples como mostrar uma mensagem num alert(), ou executar um função javascript qualquer já existente na página. Porém, com o novo cenário de aplicações Web, recheados de código Ajax, principalmente fruto do AjaxControlToolKit e derivados, a técnica não funciona mais pois a página não é mais carregada em sua totalidade, gerando o famoso postback.
A solução para isso foi a criação do método RegisterClientScriptBlock dentro da classe ScriptManager, que especificamente trata de registrar e executar um script em páginas que utilizem o controle UpdatePanel.
Um exemplo de chamada que registra um alert dentro um UpdatePanel seria:
ScriptManager.RegisterClientScriptBlock(this, this.GetType(), “scriptAjax”, “alert(’Oi’);”, true);
Detalhes a respeito do método pode ser visto no link abaixo:
http://msdn.microsoft.com/en-us/library/system.web.ui.scriptmanager.registerclientscriptblock.aspx
Abraços
Tomás
Mais uma da série: “tinha que ser mais simples”
Tudo bem que é algo meio atrevido e que inventei agora, mas algumas funções, mesmo meio “sujas”, são tão comumente necessárias no dia a dia que faria mais sentido fazerem parte dos métodos óbvios de um determinados frameworks.
Neste caso, falando em .NET, vamos ver uma forma simples de a partir de um array de strings, produzir uma única string com os itens do array separados por vÃrgula.
A necessidade apesar de parecer pouco óbvia, nasce de situações simples como interagir com sistemas legados. Um exemplo simples seria a geração de arquivos no padrão CSV, ou até mesmo sem precisar ir muito longe, montar a cláusula IN de uma consulta no padrão SQL.
Pois bem, o método que faz a proeza é o System.String.Join. O método estático requer dois parâmetros, sendo eles:
- um string que conterá o texto que separará os itens do array
- o array de strings
Veja um exemplo de código C# abaixo que roda em uma aplicação console:
string[] estacoes = new string[] { “Primavera”, “Verão”, “Outono”, “Inverno” };
string result = String.Join(”, “, estacoes);
Console.WriteLine(result); // SaÃda: “Primavera, Verão, Outono, Inverno”
Bom, confirmando o protesto inicial, poderia ser mais simples certo?
Abraços
Tomás
Parace um pouco estranho, mas geralmente dá mais trabalho é obter as informações mais óbvias e básicas. Bibliotecas e mais bibliotecas fornecem informações sobre tudo, mas o básico geralmente está além do trivial.
Uma dessas informações que me forçou a uma pesquisa na web foi como obter o nome fÃsico da página em que estava trabalhando. O nome fÃsico mesmo, por exemplo, Default.aspx. Nada mais óbvio não?
Pois bem, a linha de código não óbvia que resolver este problema é esta:
// pega o nome do arquivo da página corrente
string pageFileName = System.IO.Path.GetFileName(HttpContext.Current.Request.FilePath);
Bom, uma vez conseguida a informação, a pergunta que fica é, onde poderÃamos ou até deverÃamos usá-la? Uma situação que vivi por exemplo foi a de trabalhar com o controle MultiView. Como ele se baseia em várias Views que devem ser definidas no momento de mostrar seu conteúdo, pode ser necessária uma estrutura bem montada para fazer a troca das Views, com por exemplo, via QueryString. Neste cenário, seria necessário saber o nome da página corrente para fazer o redirecionamento correto com a QueryString montada. Claro que o nome da página poderia ser informado diretamente, mas no caso de ser necessário renomear a página por qualquer motivo, seria um problema ter que lembrar de corrigir todas as strings no código que a contém.
É isso. Bom proveito!
Tomás
A situação
Uma rotina tradicional, principalmente para quem trabalham com coleções. E para quem não sabe, trabalhar com DataTables e DataSets não o livra de usá-las pois estes objetos não passam de coleções, sejam de DataColumns, DataRows ou mesmo DataTables.
Pois bem, você executa um código “normal”, por exemplo, para remover linhas de um DataTable “varrendo” sua coleção de linhas. O código seria algo parecido com isto:
public void RemoveProducts(int ID)
{
DataTable productData = new DataTable();
productData = GetProducts(ProductID, false, true);
foreach ( dr in productData.Rows) {
if ((dr("ID") != ID.Value)) {
productData.Rows.Remove(dr);
}
}
}
Sem muitos segredos, o método preenche um DataTable e através de um laço foreach, remove as linhas que obedeçam a um determinado critério.
O problema
Qualquer código que trate coleções desta forma será muito “bem” recebido com a seguinte mensagem:
A descrição da Exception é bem genérica, mas para este caso a explicação é que, uma vez que um laço como o foreach analisa uma coleção para promover o laço, ela cria um Enumerador na primeira execução para promover um MoveNext, que fará avançar para próximo item. Se a coleção for modificada, seja por adição ou remoção de itens, o Enumerador se tornará inválido e o aplicativo retornará a Exception acima.
Abaixo segue a explicação da Microsoft para o fato:
After an enumerator is created or after the
Reset method is called, an enumerator is positioned before the first element of the collection, and the first call to the
MoveNext method moves the enumerator over the first element of the collection.
If MoveNext passes the end of the collection, the enumerator is positioned after the last element in the collection and MoveNext returns false. When the enumerator is at this position, subsequent calls to MoveNext also return false until Reset is called.
An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection, such as adding, modifying, or deleting elements, the enumerator is irrecoverably invalidated and the next call to MoveNext or Reset throws an InvalidOperationException.
Portanto, nada de mexer na coleção durante a execução de um laço foreach OK.
A solução
Se for realmente necessário construir uma rotina que altere a coleção durante a execução do laço, será preciso recorrer ao laço for tracional ao while. De qualquer forma, mesmo no for tradicional, será necessário fazer o laço de forma reversa, já que você não sabe se o último item estará lá durante a execução do laço.
Por isso a melhor forma de contruir o código sem ter problemas é varrer a coleção de trás para frente. No caso do código apresentado acima, uma possÃvel solução seria esta:
for (int i = productData.Rows.Count - 1; i >= 0; i += -1) {
    DataRow dr = productData.Rows(i);
    if ((dr("ID") != ID.Value)) {
      productData.Rows.RemoveAt(i);
    }
  }
Como dito, o laço é feito da última linha para a primeira, tomando o cuidado de sempre referenciar o Ãndice com o valor -1.
Referências
http://msdn.microsoft.com/en-us/library/system.invalidoperationexception.aspx
http://msdn.microsoft.com/en-us/library/system.collections.ienumerator.movenext.aspx
Abraços
Tomás
Não tem jeito. Apesar da imensa blibloteca que o .NET Framework possui, ainda não há (pelo menos até onde consegui pesquisar) um método nativo para comparação de Arrays ou Coleções.
Como esta foi uma necessidade que tive mais de uma vez em sistemas dos quais participei na construção, publicarei um método genérico para comparação de Arrays simples em C#.
/// <summary>
/// Compara dois arrays de string
/// </summary>
/// <param name="arrayA">Array 1</param>
/// <param name="arrayB">Array 2</param>
/// <returns>True se os arrays forem iguais,
/// False do contrário</returns>
public static bool ArrayCompare(string[] arrayA, string[] arrayB)
{
if (arrayA.Length != arrayB.Length)
{
return false;
}
for (int i = 0; i < arrayA.Length; i++)
{
if (arrayA[i] != arrayB[i])
{
return false;
}
}
return true;
}
O código abaixo completo mostra a utilização da função:
using System;
public class testCompareArrays
{
public static void Main(string[] args)
{
string[] array1 = new string[] {"a", "b", "c", "d", "e"};
string[] array2 = new string[] {"a", "b", "c", "d", "e"};
if(ArrayCompare(array1, array2))
{
Console.WriteLine("Os arrays são iguais");
}
else
{
Console.WriteLine("Os arrays são diferentes");
}
}
/// <summary>
/// Compara dois arrays de string
/// </summary>
/// <param name="arrayA">Array 1</param>
/// <param name="arrayB">Array 2</param>
/// <returns>True se os arrays forem iguais,
/// False do contrário</returns>
public static bool ArrayCompare(string[] arrayA, string[] arrayB)
{
if (arrayA.Length != arrayB.Length)
{
return false;
}
for (int i = 0; i < arrayA.Length; i++)
{
if (arrayA[i] != arrayB[i])
{
return false;
}
}
return true;
}
}
O exemplos faz uso de um array de strings, porém é simples alterá-lo para qualquer outro tipo, desde que seja nativo ou que sobrecarregue o operado ==.
Bom proveito!
Tomás