Mostrando las entradas para la consulta Manejo Valores porcentuales ordenadas por fecha. Ordenar por relevancia Mostrar todas las entradas
Mostrando las entradas para la consulta Manejo Valores porcentuales ordenadas por fecha. Ordenar por relevancia Mostrar todas las entradas

sábado, 25 de junio de 2022

Curso avanzado de C#. Formateo de cadenas

 Formatear valores

Dar formato a un valor para su visualización es una conversión de tipo particularmente importante. Hasta que no se convierta una variable Datetime, decimal o double en algún tipo de cadena, no podremos mostrarla al usuario. Dos de los métodos más útiles para formatear valores como cadenas son ToString y String. Métodos que se describen a continuación.  

ToString 

El objeto de la clase proporciona un método ToString que heredan todas las demás clases. De forma predeterminada, este método devuelve el nombre del tipo de un objeto como una cadena, pero la mayoría de las clases para las que tiene sentido anulan este método para devolver el valor del objeto como una cadena. 

Por ejemplo, si una variable float tiene el valor 1,23, el método ToString devuelve el valor "1,23" como cadena. Por el contrario, si definimos una clase empleado, de forma predeterminada el método ToString devuelve el nombre de la clase, que es similar a WindowsFormsApplication1.Employee. Si utilizamos el método ToString de una variable sin parámetros, obtenemos una representación predeterminada de su valor. El método ToString también podemos tomar como parámetros un proveedor de formato, una cadena de formato o ambos. Al utilizar la cadena de formato, podemos personalizar el texto resultante. Por ejemplo, si la variable costo es un valor flotante (float), la declaración cost.ToString ("0.00") produce una cadena que contiene el valor del costo que se muestra con 2 posiciones decimales. 

Curso avanzado de C#. Formateo de cadenas


String.Format

El método ToString nos permite convertir el valor de una sola variable en una cadena. El método de formato estático de la clase String nos permite crear una cadena que puede contener los valores de muchas variables formateadas de diferentes maneras. El método String.Format tiene algunas versiones sobrecargadas, pero la más común toma como parámetros una cadena de formato y uno o más argumentos que se utilizan para completar elementos dentro de la cadena de formato. Cada elemento en la cadena de formato tiene la siguiente sintaxis de formato compuesto: 

{index [,length] [:formatString]} 

Aquí, índex es el índice de base cero de un parámetro que sigue a la cadena de formato que debe usarse para este elemento; length es la longitud mínima del resultado del elemento; y formatString es una cadena de formato estándar o personalizada para el elemento. Si la longitud es negativa, el valor se alinea a la izquierda dentro de su longitud.

Esto formalmente lo hace parecer confuso, pero en realidad no es tan mala. El siguiente código muestra un ejemplo sencillo. 

int i = 163; 

Console.WriteLine(string.Format("{0} = {1,4} or 0x{2:X}", (char)i, i, i)); 

Utilizamos string.Format para formatear una línea que escribe en la ventana de Salida.

La cadena de formato es {0} = {1,4} or 0x{2:X}. Esta cadena tiene tres elementos de formato que significan: 

{0} muestra el argumento 0 como formato predeterminado 

{1,4} muestra el argumento 1 en un campo de al menos cuatro caracteres de ancho 

{2: X} muestra el argumento 2 con formato cadena X (que muestra un número entero en hexadecimal)

Los otros caracteres dentro de la cadena de formato (=, y or x) se incluyen en la salida tal como aparecen en la cadena de formato. 

Los parámetros que vienen después de la cadena de formato son los argumentos que deben usarse con la cadena de formato. El primer argumento convierte el entero i en un carácter. El segundo y tercer argumento son simplemente la variable i. El resultado es que esta línea muestra el valor 163 convertido en un carácter, luego como un valor decimal y luego en hexadecimal. A continuación se muestra el resultado: 

£ = 163 or 0xA3 

No es necesario utilizar un argumento en la cadena de formato. Los argumentos también se pueden usar en cualquier orden y se pueden usar repetidamente, por lo que la siguiente declaración es válida: 

string text = string.Format("{1} {4} {2} {1} {3}", 

"quién", "yo", "luego", "soy", "pienso"); 

Si utilizamos String.Format para concatenar una serie de declaraciones y producir resultados es en gran parte una cuestión de preferencia personal. 

Formateo de cadenas 

Tanto los métodos ToString como String.Format pueden tomar cadenas de formato como parámetros para indicarles cómo formatear un valor. Para String.Format, esto se refiere a la cadena de formato dentro de los elementos de formato. Por ejemplo, en la declaración string.Format("0x{0:X}", 90) , la cadena de formato es la X dentro de las llaves. Las cadenas de formato se dividen en dos categorías generales: 


Las cadenas de formato estándar permiten determinar  cómo queremos que se muestre un valor en un nivel alto.

Las cadenas de formato estándar tienen en cuenta la configuración regional, por lo que permiten que el programa produzca una salida que sea apropiada para la configuración regional del ordenador. Por ejemplo, la  cadena de formato de fecha "d" indica un patrón de  fecha corto y produce un resultado similar al 4/7/2022 en los Estados Unidos o al 7/04/2022 en España. 

Las cadenas de formato personalizadas nos permiten  crear formatos que no son proporcionados por las  cadenas de formato estándar. Por ejemplo, la siguiente declaración produce un resultado similar a:  Son las 12  en punto.

Console.WriteLine(string.Format("Son     las {0:HH} en punto",DateTime.Now)); 

Podemos usar cadenas de formato personalizadas para producir resultados que sean similares a los producidos por las cadenas estándar, pero debemos utilizar las cadenas estándar siempre que sea posible para obtener los cambios apropiados si nuestro programa se ejecuta en un ordenador que este configurada para una configuración local diferente. 

Los métodos ToString y String.Format comprenden cientos de cadenas de formato estándar y personalizadas. La tabla siguiente enumera las cadenas de formato estándar más útiles para valores numéricos y Datetime

Cadenas de formatos para números estándard

 

Formato

Descripción

Ejemplo

C o c

Moneda

12.345,67  €

D o d

Decimal, sólo tipos enteros

12345

E o e

Notación científica

1.234567E+004

F o f

Punto fujo

12345,67

G o g

General (punto fijo o científico, lo que sea más corto)

12345,67

N o n

Número con decimales y separadores de miles

12.345,67

P o p

Porcentaje (multiplicado por 100 y añadido %)

0,12 se convierte en 12 %

X o x

Hexadecimal (sólo tipos integer)

3039

 

Algunos de estos formatos pueden tener un especificador de precisión opcional que controla el número de dígitos desplegado. Para la mayoría de estos tipos, el especificador de precisión indica el número de dígitos que se mostrarán después de la coma. Por ejemplo, si el valor es 12345,67, value.ToString ("C4") produce 12.345,6700 €.

Para la notación científica, el especificador de precisión indica el número de dígitos después de la coma en la mantisa. Por ejemplo, si el valor es 12345,67, value.ToString ("E2") produce 1,23E + 004.

Cadenas de formato para Datetime

 

Formato

Descripción

Ejemplo

d

Fecha corta

7/04/2022

D

Fecha larga

Jueves 7 de abril de 2022

f

Completa con hora corta

Jueves 7 de abril de 2022 14:23

F

Completa con hora larga

Jueves 7 de abril de 2022 14:23:16

g

General con hora corta

7/04/2022 14:23

G

General con hora larga

7/04/2022 14:23:16

m o M

Dia/ mes

7 /Abril

t

Hora corta

14:23

T

Hora larga

14:23:16

y o Y

Mes / año

Abril 2022

Además de estos formatos estándar, la estructura DateTime proporciona cuatro métodos que producen una salida similar a los especificadores de formato d, D, t y T. Estos métodos son ToShortDateString, ToLongDateString, ToShortTimeString y ToLongTimeString. 

Ejemplo Visualización de valores de moneda 

Modificamos el formulario de entrada de pedidos que creamos para el Manejo Valores porcentuales para que muestre el precio extendido, el subtotal, el impuesto sobre las ventas y el total general en formato de moneda.

Solución: El programa ya usa el método ToString para mostrar esos valores. El único cambio necesario es pasar la cadena de formato de moneda "C" a esas llamadas a ToString. Por ejemplo, el siguiente código muestra cómo el programa muestra el Gran Total en formato de moneda:

txtTotal.Text = Total.ToString("C"); 


sábado, 21 de mayo de 2022

Curso avanzado de C#. Manejo de tipos dinámicos

Los atributos DllImport y MarshalAs descritos en el post anterior permiten decirle al programa dónde encontrar un método no administrado y qué tipos de datos utiliza para los parámetros y finalmente, un tipo de retorno. Esto permite que el programa invoque métodos no administrados a través de P/invoke.

COM Interop proporciona otra forma en que un programa administrado puede interactuar con código no administrado. Para usar COM Interop, necesitamos dar a nuestro   programa una referencia a una biblioteca apropiada. Para ello,  buscamos en el Explorador de soluciones, hacemos clic con el botón derecho en Referencias y seleccionamos Agregar referencia.

Manejo de tipos dinámicos C#

Buscamos la referencia que deseamos agregar en la sección Bibliotecas de tipos de la pestaña COM (por ejemplo, Biblioteca de Microsoft ActiveX Data Objects 2.0), marcamos la casilla junto a la entrada y aceptamos.

Agregar una referencia .NET con Visual Studio

Agregar una referencia de la biblioteca le dice a nuestro programa (y Visual Studio) mucho sobre la aplicación COM no administrada. Si abrimos el menú Ver y seleccionamos Explorador de objetos, podemos utilizarlo para buscar entre los objetos y tipos definidos por la biblioteca.

Examinador de Objetos Visual Studio


La biblioteca brinda a Visual Studio suficiente información para que proporcione IntelliSense sobre algunos de los miembros de la biblioteca, pero es posible que Visual Studio aún no comprenda todos los tipos usados por la biblioteca. 

Examinador de Objetos Visual Studio

Desde la versión 4.0 C# proporciona un tipo de datos especial llamado dinámico (dynamic) que podemos utilizar en esta situación. Este es un tipo de datos estático, pero su tipo verdadero no se evalúa hasta el momento de la ejecución. En el momento del diseño y la compilación, C# no evalúa el tipo de elemento dinámico, por lo que no marca errores de sintaxis para problemas tales como discrepancias de tipos porque aún no ha evaluado el tipo dinámico. Esto puede resultar útil si no podemos proporcionar información completa sobre el tipo de un elemento al compilador.

C# considera que los objetos definidos por el código COM Interop no administrado tienen tipo dinámico (dynamic),  como se ha indicado, espera hasta el tiempo de ejecución para ver si el código tiene sentido.

El programa de ejemplo ExcelInterop, utiliza el siguiente código para crear un libro de excel Microsoft Excel (previamente hemos tenido que añadir la referencia Microsoft Excel 14.0 Object Library)  :

 // Abre la aplicación excel

Excel._Application excelApp = New Excel.Application();

// añade un libro

Excel.Workbook nuevo_libro = excelApp.Workbooks.Add();

Excel.Worksheet sheet = nuevo_libro.Worksheets[1];

// Muestra el Excel.

excelApp.Visible = true;

// Pone cabeceras a las columnas.

sheet.Cells[1, 1].Value = "Valor";

sheet.Cells[1, 2].Value = "Cuadrado del Valor";

// Muestra los primeros 10 cuadrados.

For (int i = 1; i <= 10; i++)

{

sheet.Cells[i + 1, 1].Value = i;

sheet.Cells[i + 1, 2].Value = (i * i).ToString();

}

// Rellena las columnas.

sheet.Columns[1].AutoFit();

sheet.Columns[2].AutoFit();

En este código, el tipo de datos dinámicos se usa implícitamente en un par de lugares. Visual Studio no comprende realmente el tipo de datos de la hoja. Cells[1, 1], por lo que difiere la verificación de tipos para ese valor. Eso permite que el programa se refiera a la propiedad Value de esta entidad aunque el programa no sepa si la celda tiene tal propiedad. En realidad, podríamos intentar establecer sheet.Cells[1, 1].Whatever = i y Visual Studio no mostraría error hasta el momento de la ejecución, cuando intente acceder a la propiedad Whatever y descubra que no existe.

 De forma similar, Visual Studio trata a sheet.Columns[1] como si tuvieran un tipo dinámico, por lo que no sabe que el método AutoFit existe hasta el momento de la ejecución. En es siguiente código veremos un ejemplo más específico de C#.

// rellenamos un array de numeros.

int[]array1 = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

// No funciona bien por que array1.Clone es un objeto.

//int[] array2 = array1.Clone();

// Esto si funciona.

int[]array3 = (int[])array1.Clone();

array3[5] = 55;

// Esto también funciona.

dynamic array4 = array1.Clone();

array4[6] = 66;

array4[7] = "Esto no funciona";

 Este código inicializa una matriz de números enteros. El código comentado intenta usar el método Clone de la matriz para hacer una copia de la matriz. Pero el método Clone devuelve un objeto no específico, por lo que el código no puede guardarlo en una variable que se refiere a una matriz de int. Y falla. La siguiente declaración introduce correctamente el objeto en un int[] para que funcione. Después, el código almacena un nuevo valor entero en la matriz. Después, el código declara un array4 que tiene el tipo dinámico.  Se clona el array y guarda la copia en la variable array4. En tiempo de ejecución, el programa puede decir que la copia es en realidad un int[10], por lo que ese es el tipo de datos que asigna a array4.

La sentencia final intenta guardar una cadena en array4[7]. En diseño y compilación, Visual Studio no intenta validar esta declaración porque array4 se declaró dinámico. Sin embargo, en tiempo de ejecución, esto falla porque array4 es en realidad un int[] y no puede contener una cadena.

El tipo de datos dinámicos permiten evitar errores de sintaxis cuando no conocemos (o no podemos saber) el tipo de un objeto en el momento de la compilación.

Desafortunadamente, no saber el tipo de un objeto en el momento del diseño también significa que Visual Studio no puede proporcionar verificación de tipo o IntelliSense. Eso significa que debemos asegurarnos de que los métodos que invoquemos realmente existan, que asignemos valores específicos a una variable o propiedad dinámica y que no intentemos guardar un valor dinámico en una variable incompatible. El programa mostrará los errores durante la ejecución, pero no recibiremos mucha ayuda durante su diseño y compilación.

Para evitar este tipo de errores en tiempo de ejecución, debemos evitar el tipo de datos dinámicos y utilizar tipos de datos más específicos siempre que sea posible

Ejercicio de ejemplo  Formulario de pedidos

Creamos un formulario de pedidos como similar a este.

Manejo de tipos dinámicos


Este formulario de entrada de pedidos analiza (parsea) los valores numéricos y de moneda introducidos por el usuario. Cuando el usuario hace clic en el botón Aceptar, se valida el formulario, calcula y muestra los valores apropiados. (No es necesario preocuparse por formatear los campos de salida como moneda. Solo utilizaremos métodos
ToString de las variables para mostrar el texto.) Si todos los valores introducidos por el usuario son válidos, se muestra un mensaje que indica que el pedido está bien y nos pregunta si queremos continuar. Si decimos que sí

el programa realiza las siguientes operaciones:

Si alguno de los campos de una fila no está en blanco, el resto de campos de esa fila no deben estar en blanco.

La cantidad es un número entero entre 1 y 100.

El precio debe estar entre 0.01 € y $ 100,000.00 € (Hay que asegurarse  de permitir valores con formato de moneda).

La tasa de impuestos es un decimal entre 0,00 y 0,20. (No hay que preocuparse por valores porcentuales como el 7% por ciento.


No tenemos que olvidarnos de agregar una declaración using System.Globalization para poder usar NumberStyles.

Hay varias formas de estructurar el código del programa para que sea más fácil de usar y mantener. 

Debemos considerar escribir los siguientes métodos:

-DisplayErrorMessage que muestre un mensaje de error estándar y establezca el foco en un TextBox que tenga el valor no válido o faltante.

-ValidateRequiredTextBox deberá verificar que los TextBox no queden en blanco (sin rellenar).

-ValidateRow validará una fila de entrada que consta de Descripción, Cantidad y Precio de cada cuadro de texto.

Para obtener un valor de un TextBox, utilizaremos el método TryParse apropiado. Por ejemplo, el siguiente código muestra cómo leer un valor de Precio Unidad:

 // Intenta analizar priceEach.

If (!decimal.TryParse(TxtPrecio.Text, NumberStyles.Currency,

null, out precioUnidad))

{

    DisplayErrorMessage(

    "Formato no válido. El precio debe ser un     valor de tipo currency.",

    "Formáto no válido", TxtPrecio);

    Return True;

}

Este código utiliza NumberStyles.Currency para habilitar los valores de moneda.

- Debemos utilizar sentencias if para determinar si los valores se encuentran dentro de los límites esperados. El siguiente código muestra cómo el programa puede validar un valor de Price Each:

// Nos aseguramos de que el precio esté entre 0,01 y 100.000,00.

If ((priceEach < 0.01m) || (precioUnidad > 100000.00m))

{

DisplayErrorMessage(

"Formato no válido. El precio debe estar entre 0,01 y 100000,00.",

"Cantidad no válida", TxtPrecio);

Return True;

}

-Calculamos y mostramos los valores de Precio ampliado, Subtotal, Impuesto sobre las ventas y Total general. El siguiente código muestra cómo procesar la primera fila del formulario de pedido: 

subtotal = 0;

If (ValidateRow(txtDescripcion, txtCantidad, txtPrecioUnidad,

out Cantidad, out PrecioUnidad)) Return;

Precio = Cantidad * PrecioUnidad;

If (Precio == 0m) txtPrecio.Clear();

Else txtPrecio.Text = Precio.ToString();

subtotal += Precio;

Este código llama al método ValidateRow para validar y obtener los valores de Descripción, Cantidad y Precio de la primera fila. Si ese método devuelve un error al devolver true, el código retorna. Si la fila no contiene error, el código calcula Precio y muestra su valor en el TextBox apropiado. Después añade el precio extendido de la fila al valor subtotal actual y continúa procesando las otras filas.

Una forma obvia de mejorar la interfaz de usuario sería eliminar los cuadros de texto de cantidad y reemplazarlos con controles NumericUpDown. Así, el usuario puede seleccionar un valor dentro de los valores mínimos y máximos permitidos. El usuario no podía escribir basura y no podía seleccionar valores fuera del rango permitido. Incluso podemos utilizar un control NumericUpDown para la tasa impositiva estableciendo sus propiedades Mínimo = 0, Máximo = 0,2, Incremento = 0.05 y DecimalPlaces = 2.

También podemos utilizar los controles NumericUpDown para los campos PrecioUnidad, pero ese control hace que se introduzcan valores monetarios incorrectos. En general, es mejor permitir que los usuarios seleccionen un valor en lugar de introducir uno en un TextBox para que no puedan ingresar valores no válidos.

A continuación el ejemplo de código completo:

using System;

using System.Windows.Forms;

using System.Globalization;

 

namespace Ejemplo_Tipos_Dinamicos

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

        // Salida.

        private void cancelButton_Click(object sender, EventArgs e)

        {

            Close();

        }


        // Valida los valores en el formulario. Si hay errores,

        // indica al usuario y establece el foco en el TextBox apropiado.

        // Si no hay errores, muestra un mensaje de éxito y sale.

        private void okButton_Click(object sender, EventArgs e)

        {

            int cantidad;

            decimal precioUnitario, precio, subtotal;

 

            // Valida las filas. Si alguna falla, regresa.

            subtotal = 0;

            if (ValidaFila(txtDescripcion1, txtCantidad1, txtPrecioUnitario1,

                out cantidad, out precioUnitario)) return;

            precio = cantidad * precioUnitario;

            if (precio == 0m) txtPrecio1.Clear();

            else txtPrecio1.Text = precio.ToString("C");

            subtotal += precio;

 

            if (ValidaFila(txtDescripcion2, txtCantidad2, txtPrecioUnitario2,

                out cantidad, out precioUnitario)) return;

            precio = cantidad * precioUnitario;

            if (precio == 0m) txtPrecio2.Clear();

            else txtPrecio2.Text = precio.ToString("C");

            subtotal += precio;

 

            if (ValidaFila(txtDescripcion3, txtCantidad3, txtPrecioUnitario3,

                out cantidad, out precioUnitario)) return;

            precio = cantidad * precioUnitario;

            if (precio == 0m) txtPrecio3.Clear();

            else txtPrecio3.Text = precio.ToString("C");

            subtotal += precio;

 

            if (ValidaFila(txtDescripcion4, txtCantidad4, txtPrecioUnitario4,

                out cantidad, out precioUnitario)) return;

            precio = cantidad * precioUnitario;

            if (precio == 0m) txtPrecio4.Clear();

            else txtPrecio4.Text = precio.ToString("C");

            subtotal += precio;

 

            // Muestra el subtotal.

            txtSubtotal.Text = subtotal.ToString("C");

 

            // Obtiene la tasa de impuestos como una cadena.

            string IVAPorcString = txtIVAPorc.Text;

 

            // Elimina el carácter% si está presente.

            IVAPorcString = IVAPorcString.Replace("%", "");

 

            // Parsea la tasa de impuestos.

            decimal IVAPorc;

            if (!decimal.TryParse(IVAPorcString, out IVAPorc))

            {

          

                MuestraErrores(

                    "Formato no válido. el % de IVA debe ser un valor decimal.",

                    "Formato no válido", txtIVAPorc);

                return;

            }

 

            // Si la cadena original contiene el carácter%, divide entre 100.

            if (txtIVAPorc.Text.Contains("%")) IVAPorc /= 100;

 

            // Se Asegura de que la tasa de impuestos está entre 0,00 y 0,20.

            if ((IVAPorc < 0m) || (IVAPorc > 0.2m))

            {

            

                MuestraErrores(

                    "Formato no válido. El % de IVA debe estar entre  0,00 y 0,20.",

                    "Formato no válido", txtIVAPorc);

                return;

            }

 

            // En este punto tenemos todos los datos que necesitamos.

            // Calcula y muestra el impuesto sobre las ventas.

            decimal decIVA = subtotal * IVAPorc;

            txtIVATotal.Text = salesTax.ToString("C");

 

            // Calcula y muestra el total

            decimal Total = subtotal + decIVA;

            txtTotal.Text = grandTotal.ToString("C");

 

            // Muestra un mensaje de éxito  y pregunta si queremos continuar.

            if (MessageBox.Show("Orden válida. Desea Continuar?", "Continuar?",

                MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)

            {

                // Si el usuario pulsa si,  sale se deshabilita pues si no, no se ve el resultado

                //Close();

            }

        }

 

        // Valida una fila. Si hay algún valor presente, todos son obligatorios.

        // Si todos los valores están presentes, establece los parámetros de salida.

        // Si hay un error, pone el foco en el

        // cuadro de texto apropiado y devuelve true.

        private bool ValidaFila(TextBox descrTextBox, TextBox cantidadTextBox,

            TextBox precioUnitarioTextBox, out int cantidad, out decimal precioUnitario)

        {

            // Asume que hay 0.

            cantidad = 0;

            precioUnitario = 0;

 

            // Si no hay valores presentes, la fila está bien.

            if ((descrTextBox.Text == "") &&

                (cantidadTextBox.Text == "") &&

                (precioUnitarioTextBox.Text == ""))

                return false;

 

            // Se asegura de que estén todos los valores rellenos.

            if (ValidaTextBoxObligatoria(descrTextBox, "Descripcion")) return true;

            if (ValidaTextBoxObligatoria(cantidadTextBox, "Cantidad")) return true;

            if (ValidaTextBoxObligatoria(precioUnitarioTextBox, "Precio Unitario")) return true;

 

            // Todos los valores están presentes.

            // Intenta analizar (parsear)  la cantidad.

            if (!int.TryParse(cantidadTextBox.Text, out cantidad))

            {

        

                MuestraErrores(

                    "Cantidad no válida. La cantidad debe ser un valor entero.",

                    "Cantidad no válida", cantidadTextBox);

                return true;

            }

 

            // S easegura de que la cantidad esté entre 1 y 100.

            if ((cantidad < 1) || (cantidad > 100))

            {

           

                MuestraErrores(

                    "Cantidad no válida. La cantidad debe estar entre  1 y 100.",

                    "Cantidad no válida", cantidadTextBox);

                return true;

            }

 

            // Parsea el precio Unitario.

            if (!decimal.TryParse(precioUnitarioTextBox.Text, NumberStyles.Currency,

                null, out precioUnitario))

            {

 

                MuestraErrores(

                    "Precio Unitario no válido. El precio unitario debe ser un valor de tipo moneda.",

                    "Precio Unitario no válido", precioUnitarioTextBox);

                return true;

            }

 

            // Se asegura de que el precio Unitario esta entre  0,01 € y  100.000,00 €.

            if ((precioUnitario < 0.01m) || (precioUnitario > 100000.00m))

            {

              

                MuestraErrores(

                    "Precio Unitario no válido. El precio unitario debe estar entre 0,01 € and 100.000,00 €",

                    "Precio Unitario no válido", precioUnitarioTextBox);

                return true;

            }

 

            // Si llegamos aquí, tendremos todos nuestros datos.

            // Devuelve falso para indicar que no hay ningún error en esta línea.

            return false;

        }

 

        // Este TextBox es obligatorio. Si está en blanco,

        // se lo indica al usuario, le pone el foco y devuelve true

        private bool ValidaTextBoxObligatoria(TextBox txt, string name)

        {

            // Si el TextBox no está en blanco, devuelve falso.

            if (txt.Text != "") return false;

 

            // El TextBox está en blanco.

            MuestraErrores(name + " es requerido", "Valor faltante", txt);

            return true;

        }

 

        // Informa al usuario que hay un error, selecciona todos los

        // textos del TextBox y establece el foco en TextBox.

        private void MuestraErrores(string message, string title, TextBox txt)

        {

            MessageBox.Show(message, title, MessageBoxButtons.OK, MessageBoxIcon.Error);

            txt.SelectAll();

            txt.Focus();

        }

        //sale

        private void button1_Click(object sender, EventArgs e)

        {

            Close();

        }

    }

}