Mostrando entradas con la etiqueta Telerik. Mostrar todas las entradas
Mostrando entradas con la etiqueta Telerik. Mostrar todas las entradas

miércoles, 5 de junio de 2013

Utilizando el control RadNumericTextBox de Telerik

El RadNumericTextBox es uno de los controles que pertenecen al conjunto  de controles RadInput de telerik, estos controles además de permitir al usuario ingresar y editar información textual como si fuera un control TextBox ASP .NET tradicional,  poseen propiedades adicionales como: eventos del lado del cliente, marca de agua, botón para aceptar, botones para selección de rango, mensaje predeterminado, tooltip, entre otras que extienden la funcionalidad básica proporcionada por el control TextBox ASP.NET estándar.

La funcionalidad principal del RadNumericTextBox es filtrar la entrada de datos permitiendo únicamente datos numéricos sin necesidad de programación Javascript o el uso de validators ASP .NET, este control además puede configurarse para utilizar determinados formatos o configuraciones regionales. Entre las propiedades de configuración se encuentran:

  • Type Indica el formato del texto, Number para formato númerico, Currency para formato moneda, Percent para un formato porcentaje.
  • Culture Establece el soporte para la globalización y localización del valor.
  • MinValue y MaxValue Indican los valores minimos y maximos de un rango de valores.
  • ShowSpinButtons Estable la propiedad para mostrar un control de selección de flechas para el incremento o decremento del valor.

Como ejemplo del uso de este control escribí una página ASP.NET que calcula los montos de un producto deacuerdo a su cantidad y su precio, mostrando caracteristicas utiles del RadNumericTextBox como la globalización y algunas funciones del lado del cliente. (client-side)

El código de la página ASP.NET
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs"
Inherits="TestRadNumericTextBox._Default" %>
<%@ Register Assembly="Telerik.Web.UI"
Namespace="Telerik.Web.UI" TagPrefix="telerik" %>
<!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>Test RadNumeric Text Box</title>
</head>
<body>
<form id="form1" runat="server">
<telerik:RadScriptManager ID="RadScriptManager1"
runat="server">
<Scripts>
<asp:ScriptReference Assembly="Telerik.Web.UI"
Name="Telerik.Web.UI.Common.Core.js">
</asp:ScriptReference>
<asp:ScriptReference Assembly="Telerik.Web.UI"
Name="Telerik.Web.UI.Common.jQuery.js">
</asp:ScriptReference>
<asp:ScriptReference Assembly="Telerik.Web.UI"
Name="Telerik.Web.UI.Common.jQueryInclude.js">
</asp:ScriptReference>
</Scripts>
</telerik:RadScriptManager>
<telerik:RadScriptBlock ID="RadScriptBlock1"
runat="server">
<script type="text/javascript">
function Calculate() {
var ctrlQuantity = $find("txtQuantity");
var ctrlPrice = $find("txtPrice");
var ctrlSubtotal = $find("txtSubtotal");
var ctrlTaxPercent = $find("txtTax");
var ctrlTaxAmount = $find("txtTaxAmount");
var ctrlTotal = $find("txtTotal");
var quantity = parseInt(ctrlQuantity.get_value());
var price = parseFloat(ctrlPrice.get_value());
var subtotal = quantity * price;
ctrlSubtotal.set_value(subtotal);
var percent = parseFloat(ctrlTaxPercent.get_value()) * .01;
var taxAmount = subtotal * percent;
ctrlTaxAmount.set_value(taxAmount);
var total = subtotal + taxAmount;
ctrlTotal.set_value(total);
}
</script>
</telerik:RadScriptBlock>
<div>
<telerik:RadComboBox ID="cmbCultureCurrency"
runat="server"
onselectedindexchanged="cmbCultureCurrency_SelectedIndexChanged"
EmptyMessage="Select your country"
AutoPostBack="true">
<Items>
<telerik:RadComboBoxItem Text="Brazil"
Value="pt-BR" />
<telerik:RadComboBoxItem Text="United Kingdom"
Value="en-GB" />
<telerik:RadComboBoxItem Text="United States"
Value="en-US" />
<telerik:RadComboBoxItem Text="Spain"
Value="es-ES"/>
</Items>
</telerik:RadComboBox>
</div>
<br />
<table>
<tr>
<td>Product</td>
<td>
<telerik:RadComboBox ID="cmbProduct"
EmptyMessage="Select a product"
runat="server">
<Items>
<telerik:RadComboBoxItem Value="1"
Text="Potatoes" />
<telerik:RadComboBoxItem Value="2"
Text="Beans" />
<telerik:RadComboBoxItem Value="3"
Text="Apples" />
<telerik:RadComboBoxItem Value="4"
Text="Oranges" />
</Items>
</telerik:RadComboBox>
</td>
</tr>
<tr>
<td>Quantity</td>
<td>
<telerik:RadNumericTextBox ID="txtQuantity"
Runat="server"
Type="Number"
DataType="System.Uint32">
<NumberFormat ZeroPattern="n"></NumberFormat>
</telerik:RadNumericTextBox>
</td>
</tr>
<tr>
<td>Tax</td>
<td>
<telerik:RadNumericTextBox ID="txtTax"
Runat="server"
Type="Percent"
MinValue="1"
MaxValue="20"
Value="16"
ShowSpinButtons="true">
<NumberFormat ZeroPattern="n %"></NumberFormat>
</telerik:RadNumericTextBox>
</td>
</tr>
<tr>
<td>Price</td>
<td>
<telerik:RadNumericTextBox ID="txtPrice"
Runat="server"
Type="Currency"
ClientEvents-OnBlur="Calculate">
</telerik:RadNumericTextBox>
</td>
</tr>

<tr>
<td>Subtotal</td>
<td>
<telerik:RadNumericTextBox ID="txtSubtotal"
Runat="server"
Type="Currency"
DataType="System.Decimal"
ReadOnly="true">
<NumberFormat ZeroPattern="$n"></NumberFormat>
</telerik:RadNumericTextBox>
</td>
</tr>
<tr>
<td>Tax amount</td>
<td>
<telerik:RadNumericTextBox ID="txtTaxAmount"
runat="server"
ReadOnly="true">
</telerik:RadNumericTextBox>
</td>
</tr>
<tr>
<td>Total</td>
<td>
<telerik:RadNumericTextBox ID="txtTotal"
Runat="server"
Type="Currency"
DataType="System.Decimal"
ReadOnly="true">
</telerik:RadNumericTextBox>
</td>
</tr>
</table>
<div>Selected currency: <asp:Label ID="lblSelectedCurrency"
runat="server"></asp:Label></div>
</form>
</body>
</html>
El código de la clase CodeBehind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Globalization;

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

}

protected void cmbCultureCurrency_SelectedIndexChanged(object sender, 
Telerik.Web.UI.RadComboBoxSelectedIndexChangedEventArgs e)
{
CultureInfo info = null;
if (string.IsNullOrEmpty(cmbCultureCurrency.SelectedValue))
    info = System.Threading.Thread.CurrentThread.CurrentCulture;
else
    {
    info = new CultureInfo(cmbCultureCurrency.SelectedValue);
    lblSelectedCurrency.Text = cmbCultureCurrency.SelectedValue;
    txtQuantity.Culture =
    txtPrice.Culture =
    txtTaxAmount.Culture =
    txtSubtotal.Culture =
    txtTaxAmount.Culture =
    txtTotal.Culture = info;
    }
}
}
}
        

En la página ASP.NET, en el bloque JavaScript, dentro de la función Calculate() obtengo la referencia a los controles mediante la función $find(“[nombre del control]”) después utilizo las funciones get_value() y set_value() para obtener o establecer el valor. Estas funciones son del lado del cliente, porque del lado del server se hace con la propiedad Text.

function Calculate() {
var ctrlQuantity = $find("txtQuantity");
var ctrlPrice = $find("txtPrice");
var ctrlSubtotal = $find("txtSubtotal");
var ctrlTaxPercent = $find("txtTax");
var ctrlTaxAmount = $find("txtTaxAmount");
var ctrlTotal = $find("txtTotal");
var quantity = parseInt(ctrlQuantity.get_value());
var price = parseFloat(ctrlPrice.get_value());
var subtotal = quantity * price;
ctrlSubtotal.set_value(subtotal);
var percent = parseFloat(ctrlTaxPercent.get_value()) * .01;
var taxAmount = subtotal * percent;
ctrlTaxAmount.set_value(taxAmount);
var total = subtotal + taxAmount;
ctrlTotal.set_value(total);
}

En el control txtQuantity utilizo la propiedad type=”Number” lo que le da el formato numérico al valor

<telerik:RadNumericTextBox ID="txtQuantity"
Runat="server"
Type="Number"
DataType="System.Uint32">
<NumberFormat ZeroPattern="n"></NumberFormat>
</telerik:RadNumericTextBox>

El control txtTax demuestra el uso de la propiedad type=”percent”, las propiedades para el valor mínimo (MinValue), valor máximo (MaxValue) y la propiedad ShowSpinButtons.

<telerik:RadNumericTextBox ID="txtTax"
Runat="server"
Type="Percent"
MinValue="1"
MaxValue="20"
Value="16"
ShowSpinButtons="true">
<NumberFormat ZeroPattern="n %"></NumberFormat>
</telerik:RadNumericTextBox>

Los controles txtSubtotal, txtTotal y txtPrice muestran el uso de la propiedad type=Currency para dar formato de tipo moneda al valor, además en el control txtPrice utilizo el evento ClientEvents-OnBlur del lado del cliente para invocar al método Calculate definido en el bloque JavaScript.

<telerik:RadNumericTextBox ID="txtPrice"
Runat="server"
Type="Currency"
ClientEvents-OnBlur="Calculate">
</telerik:RadNumericTextBox>

Por último en el code-behind utilizo la propiedad Culture para establecer el formato en los controles RadNumericTextBox según las preferencias de la cultura seleccionada.

Al ejecutar la página ASP.NET observaras los siguientes resultados,  si el país es  Brazil, las cantidades se formatean deacuerdo a la configuración de ese país.

Si el páis seleccionado es United Kingdom, lo mismo sucede con las cantidades y con las monedas en este caso aparece el símbolo de la libra (pound).

Si el país es United States,  en las cantidades aparece el símbolo del Dollar.

Y por último si la opción del país es Spain, aparece el símbolo del Euro.

domingo, 21 de abril de 2013

Usando el control RadComboBox de Telerik con PostgreSQL

Aunque ASP.NET ofrece una extensa colección de Web Controls que proporcionan al desarrollador una programación fácil, estandarizada y orientada a objetos, también existe como parte del ecosistema de ASP.NET la suite de controles Telerik que complementan y ofrecen más funcionalidad que los Web Controls predeterminados incluidos en el conjunto estándar de ASP.NET.

Del conjunto de controles de la suite Telerik, mostraré brevemente el uso del control RadComboBox de Telerik, el cual extiende la funcionalidad proporcionada por el control DropDownList de ASP.NET al tener no solamente las características de este control sino capacidades adicionales como:la carga de datos de diferentes colecciones de datos, API con funciones de servidor y de cliente, el uso de templates para mejorar la aparencia visual y la propiedad de cargar items bajo demanda para mejorar el rendimiento.

A continuación un sencillo ejemplo para mostrar dos características básicas de este control:

  • La carga de items bajo demanda (Load on Demand)
  • El uso de templates para la aparencia visual de los items.
El ejemplo consiste de una página ASP.NET que consulta una tabla de products que contiene una lista de productos clínicos de una base de datos myinvoices, la tabla tiene el siguiente esquema:

Consultamos la lista de productos

El ejemplo esta compuesto por 6 clases: DataManager, Logger, PostgreSQLCommand,PostgreSQLDataBase, Product, ProductFilters y dos páginas ASP.NET: Default.aspx y Default2.aspx.

El código de la clase DataManager

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Npgsql;
using System.Data;
using System.Text;

namespace TestRadComboBox
{
public class DataManager
{
public List GetProducts(ProductFilters filters) {
    StringBuilder commandText = new StringBuilder("SELECT product_id, ")
    .Append("product_code, ")
    .Append("product_name ")
    .Append("FROM Products ")
    .AppendFormat("WHERE product_name Like '%{0}%'",filters.ProductName.ToUpper());
    List productList = null;
    Product p = null;
    using(NpgsqlDataReader reader = PostgreSQLCommand.GetReader(commandText.ToString(),
        null,
        CommandType.Text)){
        productList = new List();
        while (reader.Read()) {
            p = new Product();
            p.Product_ID = Convert.ToInt32(reader["product_id"]);
            p.ProductCode = reader["product_code"].ToString();
            p.ProductName = reader["product_name"].ToString();
            productList.Add(p);
        } 
    }
    return productList;
}
}
}

El código de la clase Logger

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace TestRadComboBox
{
public class Logger
{
public static void LogWriteError(string s)
{
using (FileStream stream = new FileStream("log.txt", 
    FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
    StreamWriter sw = new StreamWriter(stream);
    sw.BaseStream.Seek(0, SeekOrigin.End);
    sw.Write(s);
    sw.Flush();
    sw.Close();
}

}
}
}

El código de la clase PostgreSQLCommand

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using Npgsql;

namespace TestRadComboBox
{
internal sealed class PostgreSQLCommand
{

internal static NpgsqlDataReader GetReader(string commandText,
NpgsqlParameter[] parameters,System.Data.CommandType cmdtype){
NpgsqlDataReader resp = null;
try{
 NpgsqlConnection conn = PostgreSQLDataBase.GetInstance().GetConnection();
 using (NpgsqlCommand cmd = new NpgsqlCommand(commandText, conn))
 {
            if (parameters != null)
                cmd.Parameters.AddRange(parameters);
  resp = cmd.ExecuteReader(CommandBehavior.CloseConnection);
 }
 return resp;
}catch(Exception ex){
 Logger.LogWriteError(ex.Message);
 throw ex;
}
}
}
}

El código de la clase PostgreSQLDataBase

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Configuration;
using Npgsql;
using NpgsqlTypes;

namespace TestRadComboBox
{
internal sealed class PostgreSQLDataBase
{
static NpgsqlConnection _conn = null;
static PostgreSQLDataBase Instance = null;
string ConnectionString = null;
private PostgreSQLDataBase()
{
    try
    {
        ConnectionString = ConfigurationManager.
            ConnectionStrings["myinvoices"].ConnectionString;
    }
    catch (Exception ex)
    {
        Logger.LogWriteError(ex.Message);
        throw ex;
    }
}
private static void CreateInstance()
{
    if (Instance == null)
    { Instance = new PostgreSQLDataBase(); }
}
public static PostgreSQLDataBase GetInstance()
{
    if (Instance == null)
        CreateInstance();
    return Instance;
}
public NpgsqlConnection GetConnection()
{
    try
    {
        _conn = new NpgsqlConnection(ConnectionString);
        _conn.Open();
        return _conn;
    }
    catch (Exception ex)
    {
        Logger.LogWriteError(ex.Message);
        throw ex;
    }
}
}
}

El código de la clase Product

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

namespace TestRadComboBox
{
public class Product
{
    public int Product_ID { set; get; }
    public string ProductCode { set; get; }
    public string ProductName { set; get; }
}
}

El código de la clase ProductFilters

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

namespace TestRadComboBox
{
public struct ProductFilters
{
    public string ProductName { set; get; }

}
}

El código de la página ASP.NET Default.aspx

<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Import Namespace="TestRadComboBox" %>
<%@ Register assembly="Telerik.Web.UI" 
namespace="Telerik.Web.UI" 
tagprefix="telerik" %>
<!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>
<script runat="server">

    protected void cmbProducts_OnItemsRequested(object sender,
        RadComboBoxItemsRequestedEventArgs args) {
        DataManager dm = new DataManager();
        ProductFilters filter = new ProductFilters { 
            ProductName = args.Text
        };

        if (cmbProducts.DataSource == null)
        {
            cmbProducts.DataSource = dm.GetProducts(filter);
            cmbProducts.DataValueField = "Product_ID";
            cmbProducts.DataTextField = "ProductName";
            cmbProducts.DataBind();
        }
    }
</script>
<body>
<form id="form1" runat="server">
<telerik:RadScriptManager ID="RadScriptManager1" runat="server">
    <Scripts>
<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.Core.js">
</asp:ScriptReference>
<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQuery.js">
</asp:ScriptReference>
<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQueryInclude.js">
</asp:ScriptReference>
</Scripts>
</telerik:RadScriptManager>
<div>
Please select a product:
    <telerik:RadComboBox ID="cmbProducts" 
    DropDownWidth="333px"
    OnItemsRequested="cmbProducts_OnItemsRequested"
    EnableLoadOnDemand="true"
    Runat="server">
    </telerik:RadComboBox>
</div>
</form>
</body>
</html>


La Carga de items bajo demanda
Una de las capacidades más utilizadas del control RadComboBox es la capacidad de cargar las opciones o items bajo demanda es decir construir la consulta en base a las coincidencias de los items y lo teclado por el usuario, esta capacidad se programa con el metódo cmbProducts_OnItemsRequested

protected void cmbProducts_OnItemsRequested(object sender,
        RadComboBoxItemsRequestedEventArgs args) {
        DataManager dm = new DataManager();
        ProductFilters filter = new ProductFilters { 
            ProductName = args.Text
        };

        if (cmbProducts.DataSource == null)
        {
            cmbProducts.DataSource = dm.GetProducts(filter);
            cmbProducts.DataValueField = "Product_ID";
            cmbProducts.DataTextField = "ProductName";
            cmbProducts.DataBind();
        }
    }

En este metódo se contruye una clase ProductFilter que contine el texto tecleado por el usuario en el RadComboBox, una vez creada esta clase se pasa como argumento al metódo GetProducts de la clase DataManager dentro de este metódo se construye la consulta SQL que filtra mediante un comando LIKE la consulta de la tabla Products hacia la lista (List) que sirve de DataSource para el RadComboBox.

//Here we past the filter in order to build the SQL Query
public List GetProducts(ProductFilters filters) {
    StringBuilder commandText = new StringBuilder("SELECT product_id, ")
    .Append("product_code, ")
    .Append("product_name ")
    .Append("FROM Products ")
    .AppendFormat("WHERE product_name Like '%{0}%'",filters.ProductName.ToUpper());
    List productList = null;
    Product p = null;
    using(NpgsqlDataReader reader = PostgreSQLCommand.GetReader(commandText.ToString(),
        null,
        CommandType.Text)){
        productList = new List();
        while (reader.Read()) {
            p = new Product();
            p.Product_ID = Convert.ToInt32(reader["product_id"]);
            p.ProductCode = reader["product_code"].ToString();
            p.ProductName = reader["product_name"].ToString();
            productList.Add(p);
        } 
    }
    return productList;
}

Al ejecutar la página vemos el resultado como en las siguientes imágenes:

Se realiza la búsqueda de las coincidencias entre lo tecleado por el usuario y el listado de productos

Es característica mejora el rendimiento de los formularios.



Uso de un template para los items.

Uno de los aspectos visuales más llamativos de este control Telerik es el utilizar un template para personalizar la aparencia de la lista de elementos seleccionables, como ejemplo en la siguiente página Default2.aspx utilizamos la misma funcionalidad de la página Default.aspx con la diferencia de utilizar una tabla como template para los items.

El código de la página ASP.NET Default2.aspx que muestra el uso de un template para los items.

<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Import Namespace="TestRadComboBox" %>
<%@ Register assembly="Telerik.Web.UI" namespace="Telerik.Web.UI" 
tagprefix="telerik" %>
<!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>
<script runat="server">


protected void cmbProducts_OnItemsRequested(object sender,
    RadComboBoxItemsRequestedEventArgs args) {
    DataManager dm = new DataManager();
    ProductFilters filter = new ProductFilters { 
        ProductName = args.Text
    };

    if (cmbProducts.DataSource == null)
    {
        cmbProducts.DataSource = dm.GetProducts(filter);
        cmbProducts.DataValueField = "Product_ID";
        cmbProducts.DataTextField = "ProductName";
        cmbProducts.DataBind();
    }
}
</script>
<body>
<form id="form1" runat="server">
<telerik:RadScriptManager ID="RadScriptManager1" runat="server">
<Scripts>
<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.Core.js">
</asp:ScriptReference>
<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQuery.js">
</asp:ScriptReference>
<asp:ScriptReference Assembly="Telerik.Web.UI" Name="Telerik.Web.UI.Common.jQueryInclude.js">
</asp:ScriptReference>
</Scripts>
</telerik:RadScriptManager>
<div>
Please select a product:
<telerik:RadComboBox ID="cmbProducts" 
DropDownWidth="333px"
OnItemsRequested="cmbProducts_OnItemsRequested"
EnableLoadOnDemand="true"
HighlightTemplatedItems="true"
Runat="server">
<HeaderTemplate>
<table cellspacing="3" width="99%">
<tr>
<td width="44%">Code</td>
<td>Name</td>
</tr>
</table>
</HeaderTemplate>
<ItemTemplate>
<table cellspacing="3" width="99%">
<tr>
<td width="44%"><%#DataBinder.Eval(Container.DataItem, "ProductCode")%></td>
<td><%#DataBinder.Eval(Container.DataItem, "ProductName")%></td>
</tr>
</table>
</ItemTemplate>
</telerik:RadComboBox>
</div>
</form>
</body>
</html>

Al ejecutar la página Default2.aspx, veremos el resultado como en la siguiente imágen:

Por último el fragmento de código del archivo Web.conf del ejemplo, en donde se pone la cadena de conexión.

  <connectionStrings>
    <add connectionString="Server=127.0.0.1;Port=5432;Database=myinvoices;User ID=postgres;Password=Pa$$W0rd" name="myinvoices" />
  </connectionStrings>