Pesquisa

sábado, 2 de julho de 2011

Filtro com Check-Box para GridView

Filtro semelhante aos filtros utilizados no excel.

Segue abaixo os links:

ASP.NET GridView: How-To Add Multiple Check-Box Column Filter

Implementing pivot grid like filtration style

domingo, 1 de maio de 2011

Personalizando o HTML do UpdatePanel

Segue abaixo uma classe que tem como objetivo personalizar o HTML gerado a partir de um UpdatePanel.

namespace LeftSlipper {
using System;
using System.ComponentModel;
using System.Web.UI;
using Microsoft.Web.UI;

public class CustomUpdatePanel : UpdatePanel {
private string _cssClass;
private HtmlTextWriterTag _tag = HtmlTextWriterTag.Div;

[DefaultValue("")]
[Description("Applies a CSS style to the panel.")]
public string CssClass {
get {
return _cssClass ?? String.Empty;
}
set {
_cssClass = value;
}
}

// Hide the base class's RenderMode property since we don't use it
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new UpdatePanelRenderMode RenderMode {
get {
return base.RenderMode;
}
set {
base.RenderMode = value;
}
}

[DefaultValue(HtmlTextWriterTag.Div)]
[Description("The tag to render for the panel.")]
public HtmlTextWriterTag Tag {
get {
return _tag;
}
set {
_tag = value;
}
}

protected override void RenderChildren(HtmlTextWriter writer) {
if (IsInPartialRendering) {
// If the UpdatePanel is rendering in "partial" mode that means
// it's the top-level UpdatePanel in this part of the page, so
// it doesn't render its outer tag. We just delegate to the base
// class to do all the work.
base.RenderChildren(writer);
}
else {
// If we're rendering in normal HTML mode we do all the new custom
// rendering. We then go render our children, which is what the
// normal control's behavior is.
writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
if (CssClass.Length > 0) {
writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
}
writer.RenderBeginTag(Tag);
foreach (Control child in Controls) {
child.RenderControl(writer);
}
writer.RenderEndTag();
}
}
}
}



Abaixo, a sua aplicação.



<%@ Register Namespace="LeftSlipper" TagPrefix="ls" %>
...
<ls:CustomUpdatePanel runat="server" ID="CustomUpdatePanel1"
CssClass="greenPanel" Tag="B">
<ContentTemplate>
<asp:Label ID="Label1" runat="server"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</ls:CustomUpdatePanel>

ls:CustomUpdatePanel runat="server" ID="CustomUpdatePanel1"
CssClass="greenPanel" Tag="B">
<ContentTemplate>
<asp:Label ID="Label1" runat="server"></asp:Label>
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</ls:CustomUpdatePanel>
And here's what got rendered with these settings (actual times may vary!):

<b id="CustomUpdatePanel1" class="greenPanel">
<span id="Label1">12/6/2006 9:18:07 PM</span>
<input type="submit" name="Button1" value="Button" id="Button1" />
</b>



Este mesmo princípio pode ser utilizado para modificar qualquer controle.


Javascript - Validação Client-Side

Artigo muito interessante sobre validações.

ASP.NET Validation in Depth

Segue abaixo um dos trechos do artigo, que fala sobre as funções javascript que existem para manipular os controles de validação.

ValidatorValidate(val)
Tem como parâmetro client-validator. Esta função faz com que o seja feito a verificação e que atualize de sua exibição.

ValidatorEnable(val, enable)
Tem como parâmetro um client-validator e um valor booleano. Esta função ativa ou desativa um client-validator.

ValidatorHookupControl(control, val)
Tem como parâmetro um elemento HTML e um client-validator. Esta função modifica ou cria o vínculo entre um controle e client-validator. Logo, é possível modificar os “apontamentos” entre controle e client-validator.

Além destre trecho, existem vários outros pontos abordados sobre validações.

Fonte: MSDN

Criando Controles de Servidor Personalizados com Validação

Artigo muito interessante extraído do site devmedia, nele mostra como criar uma Class Library com customização de controles e validações.

Segue abaixo o código criado da Class Library:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text.RegularExpressions;

namespace CustomControls
{
/// <summary>
/// Tipos Predefinidos
/// </summary>
public enum TypeExpression : short
{
None, Digito, Decimal, Moeda, Email, Telefone
}

/// <summary>
/// Classe que apresenta controle TextBox com controle de validação
/// </summary>
public class CustomTextBox : Control, INamingContainer
{

private TypeExpression _valueType;

/// <summary>
/// Tipos predefinidos
/// </summary>
public TypeExpression ValueType
{
get { return _valueType; }
set { _valueType = value; }
}

/// <summary>
/// Controle de Validação
/// </summary>
RegularExpressionValidator _validator = new RegularExpressionValidator();

/// <summary>
/// Expressão de Validação
/// </summary>
public String ValidationExpression
{
get { return _validator.ValidationExpression; }
set { _validator.ValidationExpression = value; }
}

/// <summary>
/// Mensagem de Erro
/// </summary>
public String ErrorMessage
{
get { return _validator.ErrorMessage; }
set { _validator.ErrorMessage = value; }
}

/// <summary>
/// Manipula apresentação do validator
/// </summary>
public ValidatorDisplay Display
{
get { return _validator.Display; }
set { _validator.Display = value; }
}

/// <summary>
/// Controle TextBox
/// </summary>
TextBox _textBox = new TextBox();

/// <summary>
/// Propriedade Text do controle
/// </summary>
public String Text
{
get { return _textBox.Text; }
set { _textBox.Text = value; }
}

/// <summary>
/// Propriedade ID do controle
/// </summary>
public override String ID
{
get { return _textBox.ID; }
set { _textBox.ID = value; }
}

/// <summary>
/// Largura do Controle
/// </summary>
public Unit Width
{
get { return _textBox.Width; }
set { _textBox.Width = value; }
}

private Boolean _isNull;

/// <summary>
/// Preenchimento obrigatorio
/// </summary>
public Boolean IsNotNull
{
get { return _isNull; }
set { _isNull = value; }
}

/// <summary>
/// Cria controles filhos
/// </summary>
protected override void CreateChildControls()
{
// manipula TextBox
CreateTextBox();

// manipula RegularExpressionValidator
CreateRegularExpressionValidator();

// manipula RequiredFieldValidator
CreateRequiredFieldValidator();

// manipula SummaryValidator
CreateSummary();
}

/// <summary>
/// Monta TextBox e adiciona controle
/// </summary>
private void CreateTextBox()
{
// mude a aparência do controle, etc. aqui
// ex.: _textBox.CssClass = "meuCss";

// adiciona controle TextBox
Controls.Add(_textBox);
}

/// <summary>
/// Monta expressão com o tipo predefinido e adiciona (se expressão informada)
/// </summary>
private void CreateRegularExpressionValidator()
{
// fixa o controle que será validado
_validator.ControlToValidate = _textBox.ID;

// monta expressão
if (String.IsNullOrEmpty(this.ValidationExpression))
{
// verifica tipo predefinido
switch (this.ValueType)
{
case TypeExpression.Digito:
if (string.IsNullOrEmpty(this.ErrorMessage))
this.ErrorMessage = "Somente dígitos.";
this.ValidationExpression = @"^\d+$";
break;
case TypeExpression.Decimal:
if (string.IsNullOrEmpty(this.ErrorMessage))
this.ErrorMessage = "Formato decimal inválido.";
this.ValidationExpression = @"^[+-]?((\d+|\d{1,3}(\.\d{3})+)(\,\d*)?|\,\d+)$";
break;
case TypeExpression.Moeda:
if (string.IsNullOrEmpty(this.ErrorMessage))
this.ErrorMessage = "Formato moeda inválido.";
this.ValidationExpression = @"^\d{1,3}(\.\d{3})*\,\d{2}$";
break;
case TypeExpression.Email:
if (string.IsNullOrEmpty(this.ErrorMessage))
this.ErrorMessage = "Formato e-mail inválido.";
this.ValidationExpression = @"^([\w\-]+\.)*[\w\- ]+@([\w\- ]+\.)+([\w\-]{2,3})$";
break;
case TypeExpression.Telefone:
if (string.IsNullOrEmpty(this.ErrorMessage))
this.ErrorMessage = "Formato telefone inválido.";
this.ValidationExpression = @"^\(\d{3}\)-\d{4}-\d{4}$";
break;
}
}

// adiciona controle (se conter expressão)
if(!String.IsNullOrEmpty(this.ValidationExpression))
Controls.Add(_validator);
}

/// <summary>
/// Monta RequiredFieldValidator e adiciona (se campo obrigatorio)
/// </summary>
private void CreateRequiredFieldValidator()
{
// se campo obrigatorio
if (this.IsNotNull)
{
// cria RequiredFieldValidator e fixa propriedades
RequiredFieldValidator _required = new RequiredFieldValidator();
_required.ControlToValidate = this.ID;
// ** sugestão: crie uma propriedade para esta
// mensagem de erro
_required.ErrorMessage = String.Empty;
_required.Text = "* obrigatorio";
_required.Display = ValidatorDisplay.Dynamic;
_required.ForeColor = System.Drawing.Color.Red;

// adiciona controle
Controls.Add(_required);
}
}

/// <summary>
/// Monta ValidationSummary e adiciona (se possuir validação)
/// </summary>
private void CreateSummary()
{
// verifica as propriedades obrigatorias
if (!String.IsNullOrEmpty(this.ValidationExpression) || this.IsNotNull)
{
// contador de verificação dos controles CustomTextBox
Int16 count = 0;
// percorre todos os controles da página
foreach (Control _control in Page.Form.Controls)
{
// se controle for do tipo da classe
// personalizada que estamos desenvolvendo
if (_control.GetType() == typeof(CustomTextBox))
{
// se o objeto está sendo acessado pela
// primeira vez
if (count == 0)
// se o controle encontrado é o controle que
// provocou a chamada
if (_control.ID == this.ID)
{
// cria Summary e fixa propriedades
ValidationSummary _summary = new ValidationSummary();
// ** sugestão: preencha esta propriedade
// para mensagem comuns
//_summary.HeaderText = "Verifique os
// campos Obrigatórios.";
_summary.ShowMessageBox = true;
_summary.ShowSummary = false;
_summary.ID = "vsTextBox";
_summary.DisplayMode = ValidationSummaryDisplayMode.List;

// adiciona controles
Controls.Add(_summary);
}
// incrementa à quantidade de controles do
// tipo CustomTextBox encontrados
count++;
}
}
}
}
}
}



E aqui, a aplicação da Class Library e uma página:



< %@ Page Language="VB" AutoEventWireup="false" CodeFile="Validation.aspx.vb" Inherits="Default5" %>

< %@ Register Assembly="CustomControls" Namespace="CustomControls" TagPrefix="cc1" %>

< !DOCTYPE html PUBLIC " -//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >

< html xmlns="http://www.w3.org/1999/xhtml" >
< head runat="server" >
< title>Untitled Page< /title>
< /head>
< body>
< form id="form1" runat="server" >
< div>
< !-- campo obrigatorio -->
< cc1:CustomTextBox ID="CustomTextBox1" runat="server" IsNotNull="true" />< br />
< !-- campo obrigatorio e somente dígito -->
< cc1:CustomTextBox ID="CustomTextBox2" runat="server" ValueType="Digito" Display="None" IsNotNull="true" />< br />
< !-- campo não obrigatorio com validaç ão de e-mail e mensagem de erro externo -->
< cc1:CustomTextBox ID="CustomTextBox3" runat="server" ValueType="Email" Display="Dynamic" ErrorMessage="E-mail inválido" />< br />
< !-- campo não obrigatorio com validaç ão de telefone e mensagem de erro interna -->
< cc1:CustomTextBox ID="CustomTextBox4" runat="server" ValueType="Telefone" Display="Static" />< br />
< asp:Button ID="Button1" runat="server" Text="Button" />
< /div>
< /form>
< /body>
< /html>



Fonte: DevMedia

segunda-feira, 7 de março de 2011

Formatar dinheiro R$

Para exibir na forma de String uma variável float ou decimal basta aplicar as regras do String.Format com a utilização de duas casas decimais.

Abaixo um exemplo de como pode ser formatado:

System.Globalization.CultureInfo culturaBrasileira = 
new System.Globalization.CultureInfo("pt-BR");
String dinheiroFormatado = String.Empty;
float dinheiro = 45612.54F;

dinheiroFormatado = String.Format(culturaBrasileira, "R$ {0:F2}", dinheiro);




Customização RadioButtonList

O controle RadioButtonList gera uma série de tags HTML que para o desenvolvimento do CSS acaba dificultando sua estilização. Além disso, semânticamente o HTML gerado deveria ser baseado em UL (<UL>) e LI (<LI>).

Assim como na customização do updatepanel, basta sobrescrever o método responsável pela geração do HTML. Neste caso, o método Render.

Abaixo tem um exemplo:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace Customizado.ControlLibrary
{
[ToolboxData("<{0}:CustomizadoRadioButtonList runat=server></{0}:CustomizadoRadioButtonList>")]
public class CustomizadoRadioButtonList : System.Web.UI.WebControls.RadioButtonList
{
protected override void Render(HtmlTextWriter writer)
{
// We start our un-ordered list tag.
writer.WriteBeginTag("ul");

// If the CssClass property has been assigned, we will add
// the attribute here in our <ul> tag.
if (this.CssClass.Length > 0)
{
writer.WriteAttribute("class", this.CssClass);
}

// We need to close off the <ul> tag, but we are not ready
// to add the closing </ul> tag yet.
writer.Write(">");

// Now we will render each child item, which in this case
// would be our checkboxes.
for (int i = 0; i < this.Items.Count; i++)
{
// We start the <li> (list item) tag.
writer.WriteFullBeginTag("li");

this.RenderItem(ListItemType.Item, i, new RepeatInfo(), writer);

// Close the list item tag. Some people think this is not
// necessary, but it is for both XHTML and semantic reasons.
writer.WriteEndTag("li");
}

// We finish off by closing our un-ordered list tag.
writer.WriteEndTag("ul");
}
}
}



Fonte: http://www.singingeels.com/Articles/Semantic_CheckBoxList__RadioButtonList.aspx

Customização UpdatePanel

Para personalizar a tag HTML que é gerada pelo update panel, basta sobrescrever o método RenderChildren.

Abaixo tem um exemplo baseado de um post estraído do http://weblogs.asp.net.

Pode-se customizar até mesmo a classe que será utlizado no elemento do UpdatePanel.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;

namespace Customizado.ControlLibrary
{
[ToolboxData("<{0}:CustomizadoUpdatepanel runat=server></{0}:CustomizadoUpdatepanel>")]
public class CustomizadoUpdatepanel : System.Web.UI.UpdatePanel
{
private string cssClass;
private HtmlTextWriterTag elemento = HtmlTextWriterTag.Div;

[DefaultValue("")]
[Description("Applies a CSS style to the panel.")]
public string CssClass
{
get
{
return cssClass ?? String.Empty;
}
set
{
cssClass = value;
}
}

// Hide the base class's RenderMode property since we don't use it
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new UpdatePanelRenderMode ModoRenderizar
{
get
{
return base.RenderMode;
}
set
{
base.RenderMode = value;
}
}

[DefaultValue(HtmlTextWriterTag.Div)]
[Description("A tag para renderizar o painel")]
public HtmlTextWriterTag Elemento
{
get
{
return elemento;
}
set
{
elemento = value;
}
}

protected override void RenderChildren(HtmlTextWriter escrever)
{
if (IsInPartialRendering)
{
// If the UpdatePanel is rendering in "partial" mode that means
// it's the top-level UpdatePanel in this part of the page, so
// it doesn't render its outer tag. We just delegate to the base
// class to do all the work.
base.RenderChildren(escrever);
}
else
{
// If we're rendering in normal HTML mode we do all the new custom
// rendering. We then go render our children, which is what the
// normal control's behavior is.
escrever.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
if (CssClass.Length > 0)
{
escrever.AddAttribute(HtmlTextWriterAttribute.Class, CssClass);
}
escrever.RenderBeginTag(Elemento);
foreach (Control filho in Controls)
{
filho.RenderControl(escrever);
}
escrever.RenderEndTag();
}
}
}
}



quarta-feira, 2 de março de 2011

Yield - Retornar uma instância do tipo IEnumerable ou IEnumerator

O Yield é utilizado para retornar uma instância do tipo IEnumerable ou IEnumerator, em casos que eu tenho um método que retorne vários valores, o ganho de performance é considerável se você tem uma coleção de dados extensa, observe abaixo:

Confira abaixo como utilizar o yield:

class Program
{
static void Main(string[] args)
{
foreach (int num in ObterLista())
{
Console.WriteLine(num);
}
}

public static IEnumerable ObterLista()
{
for (int i = 0; i < 100; i++)
{
yield return i;
}
}
}


public IEnumerable GetImpares_Yield(Int32 maxNum)
{
int num = 0;

while (true)
{
System.Threading.Thread.Sleep(1000);
num++;

if (num % 2 == 1)
yield return num;

if (num >= maxNum)
yield break;
}
}


Créditos: http://devrs.net/post/desmistificando-o-yield/

segunda-feira, 3 de janeiro de 2011

Imagem com cantos arredondados

Para fazer imagens com cantos arredondados sem que aconteça problemas em diferentes navegadores, basta renderizar as imagens no servidor.

Segue abaixo um exemplo de como fazer:

Pagina RoundCorner.aspx:

Página responsável por ajustar os cantos das imagens.

<%@ Page Language="C#" %>
<%@ Import Namespace="System.Drawing" %>

<script runat="server">

void Page_Init(Object sender,EventArgs e) {

string imagem = Request.QueryString["Imagem"].ToString();
string path = Server.MapPath(String.Format("~/{0}", imagem));
int roundedDia = 20;

using(System.Drawing.Image imgin = System.Drawing.Image.FromFile(path)){

System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(imgin.Width, imgin.Height);
Graphics g = Graphics.FromImage(bitmap);

//Define a cor do canto arredondado
Color cor = Color.FromArgb(29, 29, 29);
g.Clear(cor);

Brush brush = new System.Drawing.TextureBrush(imgin);

FillRoundedRectangle(g, new Rectangle(0, 0, imgin.Width, imgin.Height), roundedDia, brush);

// done with drawing dispose graphics object.

g.Dispose();

// Stream Image to client.

Response.Clear();

Response.ContentType = "image/pjpeg";

bitmap.Save(Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);

Response.End();

// dispose bitmap object.

bitmap.Dispose();
}
}

public static void FillRoundedRectangle(Graphics g,Rectangle r,int d,Brush b){

// anti alias distorts fill so remove it.
System.Drawing.Drawing2D.SmoothingMode mode = g.SmoothingMode ;

g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
g.FillPie(b,r.X,r.Y,d,d,180,90);
g.FillPie(b,r.X+r.Width-d,r.Y,d,d,270,90);
g.FillPie(b,r.X ,r.Y+r.Height -d,d,d,90,90);
g.FillPie(b,r.X +r.Width-d,r.Y+r.Height -d,d,d,0,90);
g.FillRectangle(b,r.X + d/2,r.Y,r.Width-d,d/2);
g.FillRectangle(b,r.X ,r.Y +d/2,r.Width,r.Height-d);
g.FillRectangle(b,r.X + d/2,r.Y + r.Height-d/2,r.Width-d,d/2);
g.SmoothingMode = mode;
}

</script>

Página que utiliza a RoundCorner.aspx:


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Image runat="server" ID="img" ImageUrl="~/RoundCorner.aspx?Imagem=imagem.jpg" />
</div>
</form>
</body>
</html>

Créditos: Tiago Bandeira


Select em Stored Procedure

Para não ter que reescrever a lógica existente em uma stored procedure para fazer um simples select, basta inserir o conteudo de uma stored procedure para dentro de uma tabela temporária.

É praticamente como utilizar a stored procedure no lugar da tabela.

Segue abaixo o exemplo:

-- DROP PROCEDURE testProc
-- DROP TABLE #testTable

CREATE PROCEDURE testProc AS
BEGIN
SELECT 'AB' as col1, 'CD' as col2
UNION
SELECT 'EF' as col1, 'GH' as col2
END

GO
CREATE TABLE #testTable (col1 varchar(5), col2 varchar(5))

GO
-- this call will succeed
INSERT INTO #testTable EXEC testProc

GO
SELECT * FROM #testTable where col2 like '%C%'



Gerar imagem com texto

Gerar imagem com texto personalizado.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="gerar-imagem.aspx.cs" Inherits="gerar_imagem" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox runat="server" ID="Text" />
<br>
<br>
<asp:DropDownList runat="server" ID="BackgroundColor">
<asp:ListItem Value="red">Red</asp:ListItem>
<asp:ListItem Value="green">Green</asp:ListItem>
<asp:ListItem Value="navy">Navy</asp:ListItem>
<asp:ListItem Value="orange">Orange</asp:ListItem>
</asp:DropDownList>
<asp:DropDownList runat="server" ID="Font">
<asp:ListItem Value="Arial">Arial</asp:ListItem>
<asp:ListItem Value="Verdana">Verdana</asp:ListItem>
<asp:ListItem Value="Courier">Courier</asp:ListItem>
<asp:ListItem Value="Times New Roman">Times New Roman</asp:ListItem>
</asp:DropDownList>
<br>
<br>
<asp:Button runat="Server" ID="SubmitButton" Text="Gerar Imagem" />
</div>
</form>
</body>
</html>



using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.Drawing.Text;
using System.Drawing.Imaging;

public partial class gerar_imagem : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if(Page.IsPostBack)
{
Bitmap oBitmap = new Bitmap(468, 60);
Graphics oGraphic = Graphics.FromImage(oBitmap);
System.Drawing.Color oColor = new Color();

String sColor = Request["BackgroundColor"];
String sText = Request["Text"];
String sFont = Request["Font"];

switch (sColor)
{
case "red":
oColor = Color.Red;
break;
case "green":
oColor = Color.Green;
break;
case "navy":
oColor = Color.Navy;
break;
case "orange":
oColor = Color.Orange;
break;
default:
oColor = Color.Gray;
break;
}
SolidBrush oBrush = new SolidBrush(oColor);
SolidBrush oBrushWrite = new SolidBrush(Color.White);

oGraphic.FillRectangle(oBrush, 0, 0, 468, 60);
oGraphic.TextRenderingHint = TextRenderingHint.AntiAlias;

Font oFont = new Font(sFont, 13);
PointF oPoint = new PointF(5, 5);

oGraphic.DrawString(sText, oFont, oBrushWrite, oPoint);

oBitmap.Save(Server.MapPath("gen_img.jpg"), ImageFormat.Jpeg);

Response.Write("Imagem gerada <a target=\"_blank\" href=\"gen_img.jpg\">aqui</a>");
}
}
}



Desabilitar botão após o click

Solução muito simples para desabilitar o botão após o click.

Essa solução pode ser utilizado em requisições ajax, com update panel.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<asp:ScriptManager ID="scriptManager" AsyncPostBackTimeout="0" runat="server">
</asp:ScriptManager>
<div>
<asp:UpdatePanel runat="server" ID="upPrincipal">
<ContentTemplate>
<asp:Button runat="server" ID="btnSalvar" Text="Salvar"
onclick="btnSalvar_Click" />
<asp:Literal runat="server" ID="ltlTexto"></asp:Literal>
</ContentTemplate>
</asp:UpdatePanel>

</div>
</form>
</body>
</html>

E no code behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
btnSalvar.Attributes.Add("onclick", "this.disabled=true;" + Page.ClientScript.GetPostBackEventReference(btnSalvar, String.Empty).ToString());
}
protected void btnSalvar_Click(object sender, EventArgs e)
{
System.Threading.Thread.Sleep(5000);
ltlTexto.Text += DateTime.Now.ToString() + " - ";
}
}