Go to content Go to navigation Go to search

C# – Easily consuming an XML or RSS feeds hosted on the web

August 14th, 2010 by JuanK

Many times we need to read an RSS or XML content from the web, and we need it fast, light and easy to use.

Searching the Internet, you can get several solutions in several different flavors. In this article I’d teach how to build a component capable of read any XML that is on the web in order to access your information easily and by the way to explain What to do to take full advantage when that XML is a RSS .

We can split the problem in 2 parts:

  • Get the XML or RSS Web
  • Access to such information by a well-known component, a DataSet

 

GET THE RSS OR XML FROM THE WEB

To achieve this objective it’s necessary to make use of an HttpWebRequest object to create a request to the URL where the XML is hosted and then to capture the answer (response).

public static DataSet GetXMLDataSet(string URL)
{
    HttpWebRequest xmlRequest = (HttpWebRequest)WebRequest.Create(URL);
    WebResponse xmlResponse = xmlRequest.GetResponse();  
}

 

ACCESS TO THIS INFORMATION THROUGH A KNOWN, A DATASET COMPONENT

Although we already have the WebResponse this cannot allow us for ‘multi-purpose’ access to the information it contains, but because we know that our WebResponse contains XML information, We can take it to create a DataSet.

You can create the DataSet of a Stream so we will use the GetResponseStream method to obtain it, we created a void DataSet and then we fill it with ReadXml.

public static DataSet GetXMLDataSet2(string URL)
{
    HttpWebRequest xmlRequest = (HttpWebRequest)WebRequest.Create(URL);
    WebResponse xmlResponse = xmlRequest.GetResponse();
    Stream responseStream = xmlResponse.GetResponseStream();
 
    DataSet xmlData = new DataSet();
    xmlData.ReadXml(responseStream);
    return xmlData;
}

By reducing code a little:

public static DataSet GetXMLDataSet(string URL)
{
    HttpWebRequest xmlRequest = (HttpWebRequest)WebRequest.Create(URL);
    DataSet xmlData = new DataSet();
    xmlData.ReadXml(xmlRequest.GetResponse().GetResponseStream());
    return xmlData;
}

That’s all, now is time to take advantage of the DataSet .

 

ADDITIONAL NOTE

Some RSS have a little more complex structures that can bring problems to create the DataSet, usually this problem throws System.Data.DuplicateNameException exception, to avoid this problem, it is necessary to tell the DataSet which is the correct structure of the RSS, so we use ReadXmlSchema loading the XSD schema that describes the structure of RSS 2.0, to obtain it just go to this page and download it: RSS 2.0 Schema, more specifically this link rss-2_0.xsd.

We add the xsd file to the project embedded resource, the code look like this:

/// <summary>
/// Se conecta a una URL que representa un archivo XML y convierte la información en un DataSet</summary>
/// <param name="URL">URL del xml publicado en la web</param>
/// <returns>Dataset que representa los datos XML</returns>
public static DataSet GetXMLDataSet(string URL)
{
    HttpWebRequest xmlRequest = (HttpWebRequest)WebRequest.Create(URL);
    DataSet xmlData = new DataSet();
    xmlData.ReadXmlSchema(new XmlTextReader(Resources.rss_2_0, XmlNodeType.Document,null));
    xmlData.ReadXml(xmlRequest.GetResponse().GetResponseStream(), XmlReadMode.IgnoreSchema);
    return xmlData;
}
Bookmark and Share

C# – 10 pasos para Consumir el RSS de Top news de “The Washington Post” en un Toolbar para IE

June 14th, 2010 by JuanK

Hola, hace unos meses escribí este artículo acerca de esta herramienta: “Add-In Express for IE”  que facilita enormemente la creación add-ons para Internet Explorer : C# – Creando Toolbars, Botones y Menús para Internet Explorer

 

Llegué a esta herramienta gracias a un proyecto importante que esta desarrollando Microsoft en el país, me han contactado para llevarlo a cabo y de paso me contaron que utilizarían esta herramienta para llevar a cabo este proyecto.

 

Como lo mencione anteriormente al comienzo creí que sería un proyecto realizado con IE SDK y COM pero apenas me confirmaron de la existencia de esta herramienta me puse en la labor de documentarme a través de internet.

 

Construir un Addon para IE es algo bastante interesante y en esencia sencillo de realizar haciendo uso de “Add-In Express for IE”.

Me detuve por unos instantes a pensar que cosas se pueden hacer con esta herramienta y me di cuenta que para sacarle máximo provecho es conveniente idear componentes dinámicos que permitan al usuario interactuar de manera directa con el contenido desplegado en el toolbar, sidebar o botón.

 

Dentro de los miles de diferentes alternativas que puedan existir para crear componentes dinámicos he optado por tratar 2 temas:

  • Consumo de RSS para despliegue de información
  • Crear una caja de búsqueda

 

En este artículo enseñaré como crear un componente Add-In Express for IE que consumiendo datos de un RSS se comporte de manera dinámica.

 

Creare un componente que lea el RSS de Top News desde The Washington Post y despliegue esos datos como un texto con híper vínculo. Ese componente lo colocare en un toolbar para IE.

 

CONSUMIR EL RSS DE TOP NEWS

Esta tarea la puedo realizar haciendo uso de este sencillo método que he creado:

C# – Consumir un XML o un RSS alojado en la web de manera sencilla

 

Simplemente llamaré al método pasándole la URL del RSS de Top News: http://www.washingtonpost.com/wp-dyn/rss/linkset/2005/03/24/LI2005032400102.xml

 

PASO 1 – CREAR EL PROYECTO

 

image

 

PASO 2 – CREAR UNA CLASE QUE ALOJE EL METODO PARA CONSUMIR EL RSS

using System.Net;
using System.Data;
 
/// <summary>Provee funcionalidades de conexión a una URL que publica un archivo XML</summary>
public static class RemoteXML
{
    /// <summary>
    /// Se conecta a una URL que representa un archivo XML y convierte la información en un DataSet
    /// </summary>
    /// <param name="URL" />URL del xml publicado en la web</param>
    /// <returns>Dataset que representa los datos XML</returns>
    public static DataSet GetXMLDataSet(string URL)
    {
        HttpWebRequest xmlRequest = (HttpWebRequest)WebRequest.Create(URL);
        DataSet xmlData = new DataSet();
        xmlData.ReadXml(xmlRequest.GetResponse().GetResponseStream());
        return xmlData;
    }
}

 

PASO 3 – CREAR UN TOOLBAR

Esto es sencillísimo gracias a “Add-In Express for IE”, tan solo:

  • clic derecho sobre el proyecto
  • adicionar nuevo ítem
  • y…

 

image

 

PASO 4 – CREAR UN LABEL PARA MOSTRAR EL CONTENIDO DEL RSS Y HACER LINK

El toolbar como tal es un Panel vacio así que arrastro allí un nuevo label, la mejor parte es que los controles para adicionar en el toolbar son los mismos controles de Windows Forms :) ( he colocado colores distintos para distinguir los controles ).

 

image

 

PASO 5 – CONSUMIR EL RSS Y TOMAR LA PRIMERA NOTICIA

Ahora utilizando el método del paso 2 tomare el RSS y hare uso de la primera noticia. Para tal fin he creado una estructura RSSEntryInfo:

/// <summary>Representa información de una entrada RSS</summary>
public struct RSSEntryInfo
{
   public string title, url;
}

 

Seguidamente creo el siguiente método dentro de la clase RemoteXML:

/// <summary>
/// Devuelve la última entrada de un RSS
/// </summary>
/// <returns></returns>
private static RSSEntryInfo GetLatestRSSEntry(string RSSUrl)
{
    RSSEntryInfo ni = new RSSEntryInfo();
 
    try
    {
        using (var datos = RemoteXML.GetXMLDataSet(RSSUrl))
        {
            foreach (DataRow row in datos.Tables[&quot;item&quot;].Select())
            {
                ni.title = (string)row[&quot;title&quot;];
                try
                {
                    ni.url = (string)row[&quot;link&quot;];
                }
                catch 
                {
                    ni.url = ((Uri)row[&quot;link&quot;]).AbsoluteUri;
                }
                break;
            }
        }
    }
    catch
    {
        throw;
    }
 
    return ni;
}

 

Es IMPORTANTE tener cuenta que si la implementación de GetXMLDataSet incluye la carga del XSD de RSS 2.0 entonces el URL vendrá en formato de objeto Uri. Ver "Nota Adicional" al final de el artículo:

C# – Consumir un XML o un RSS alojado en la web de manera sencilla

 

PASO 6 – CONFIGURAR EL LABEL CON LA INFORMACION OBTENIDA DEL RSS

Ahora hay que configurar el label con la información, para ello he creado un método lblLastTopNewInfo dentro del código del toolbar, y he creado una variable string para almacenar la URL de la última noticia. Acá utilizo el RSS de top news de The Washington Post: http://www.washingtonpost.com/wp-dyn/rss/linkset/2005/03/24/LI2005032400102.xml

/// <summary>URL donde esta la noticia contenida en el label</summary>
string ltnUrl;
/// <summary>Trae la última noticia de un RSS y establece la información necesaria en el label</summary>
private void lblLastTopNewInfo()
{
    var ltnInfo = RemoteXML.GetLatestRSSEntry(&quot;http://www.washingtonpost.com/wp-dyn/rss/linkset/2005/03/24/LI2005032400102.xml&quot;);
    lblLastTopNew.Text = ltnInfo.title;
    ltnUrl = ltnInfo.url;
}

 

PASO 7 – PROGRAMAR EL EVENTO CLIC DEL LABEL PARA HACER QUE IE NAVEGUE A LA URL DE LA ULTIMA NOTICIA

Para poder hacer que IE navegue al URL de la última noticia hare uso de otra de las funcionalidades de “Add-In Express for IE”, cada objeto creado ( toolbar, bar, etc ) tiene dos referencias a IE una de ellas a un tipo object, y la otra al mismo tipo object pero accediéndolo como Interop.SHDocVw.WebBrowser, esto facilita enormemente trabajar con el browser, en cada objeto de “Add-In Express for IE” tenemos esta referencia en el campo IEApp.

Así queda el evento clic del label:

/// <summary>
/// Hace que IE navegue al URL correspondiente
/// </summary>
/// <param name="sender" /></param>
/// <param name="e" /></param>
private void lblLastTopNew_Click(object sender, EventArgs e)
{
    object nullObject =null;
    this.IEApp.Navigate(ltnUrl, ref nullObject,
        ref nullObject, ref nullObject, ref nullObject);
}

 

PASO 8 – HACER QUE EL LABEL ARRANQUE CON LA INFORMACION DEL RSS

Para ello programo el evento OnConnect del toolbar, este evento se dispara cada vez que el Toolbar se integra con IE.

/// <summary>
/// Configura el estado inicial del label
/// </summary>
/// <param name="sender" /></param>
/// <param name="threadId" /></param>
private void TWPToolbar_OnConnect(object sender, int threadId)
{
    lblLastTopNewInfo();
}

 

PASO 9 – HACER QUE CADA HORA SE REFRESQUE LA ULTIMA NOTICIA

Con un System.Timers.Timer establezco que cada 30 minutos se llame a lblLastTopNewInfo()

/// <summary>Temporizados para refrescar la última noticia</summary>
System.Timers.Timer timerWpLn = new System.Timers.Timer();
 
/// <summary>
/// Configura el estado inicial del toolbar
/// </summary>
/// <param name="sender" /></param>
/// <param name="threadId" /></param>
private void TWPToolbar_OnConnect(object sender, int threadId)
{
    lblLastTopNewInfo();
    timerWpLn.Interval = 1000 * 60 * 30;
    timerWpLn.Elapsed += new System.Timers.ElapsedEventHandler(timerWpLn_Elapsed);
    timerWpLn.Enabled = true;
    timerWpLn.Start();
}
 
/// <summary>
/// Establece periodicamente los valores del label
/// que muestra la última noticia
/// </summary>
/// <param name="sender" /></param>
/// <param name="e" /></param>
void timerWpLn_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    lblLastTopNewInfo();
}

 

Adicionalmente he coloreado el label de color azul, y he hecho que al pasar el mouse por encima del control el cursor del mouse cambie para mostrar que es un híper vínculo, esto en los eventos MouseEnter y MouseLeave.

 

PASO 10 – INTEGRAR, COMPILAR Y PROBAR EN IE

Esto es muy fácil, das doble clic sobre IEModule para abrir el panel del módulo, voy a las propiedades del módulo y entro donde dice toolbars :

image 

Allí agrego un nuevo toolbar y lo configuro como se ve en esta imagen:

image 

compilo la solución, luego clic derecho en el proyecto y selecciono Register ADX Project,

 

image

 

abro IE y listo! … ver video abajo.

 

http://www.youtube.com/v/ovIZtcmkkNA

Bookmark and Share

Como cambiar el texto de los botones de un MessageBox – C#

June 13th, 2010 by JuanK

Por razones que aún no me son del todo claras, el .NET Framework no tiene textos localizables para los MessageBox, razón por la cual no siempre se muestran en el lenguaje que necesitamos, sino que se muestran en el lenguaje del Framework instalado.

 

Puede que nuestra aplicación este en español pero probablemente nuestros MessageBox siempre salgan con los labels de los botones en ingles:

image

Además no siempre los labels de los batones tienen textos convenientes para nuestras aplicación.

El Framework no nos ofrece ninguna manera de modificar dichos textos más allá de las opciones predeterminadas, ¿Qué podemos hacer?

No es una tarea tan sencilla como uno se imaginaria inicialmente, requiere del uso de la API de Windows y un poco de ingenio.

He creado una utilidad que te ahorrará mucho trabajo y podrás cambiar los textos de los botones de manera muy sencilla tal como te lo muestra el siguiente ejemplo:

MsgBoxUtil.HackMessageBox("SI","NO", "CANCELAR");
            MessageBox.Show("hola", "hola", MessageBoxButtons.YesNoCancel);
            
            MsgBoxUtil.HackMessageBox("REINTENTAR", "CANCELAR");
            MessageBox.Show("hola2", "hola2", MessageBoxButtons.RetryCancel);
            
            MsgBoxUtil.HackMessageBox("Descartar", "Reintentar", "Ignorar");
            MessageBox.Show("hola3", "hola3", MessageBoxButtons.AbortRetryIgnore);
            
            MsgBoxUtil.UnHackMessageBox();
 
            MessageBox.Show("Normal", "Normal", MessageBoxButtons.AbortRetryIgnore);

 

El código completo de la utilidad lo puedes descargar aquí: MsgBoxUtil.cs

 

Cómo se hace?

Bueno hay que hacer las cosas al derecho, primero lo primero.

Análisis

Planteamiento inicial

  • Para modificar los textos hay que encontrar la manera de llegar hasta los botones del MessageBox
  • Para llegar a los botones del MessageBox primero hay que llegar al MessageBox

 

Dado que el .NET Framework no nos permite manipular la ventana del MessageBox debemos recurrir a la API de Windows.

Para Windows, todo control que se dibuje en pantalla es una ventana ( si, así es), así que si tuviéramos una forma, esta es una ventana que contiene paneles, los panales son también ventanas que contienen por ejemplo GroupBox que a su vez son ventanas que contienen botones , que a su vez también son ventanas.

Con base a estos puntos entonces detallemos un poco más el planteamiento.

  • Se deben buscar las ventanas hijas de la forma actual
  • Cuando se encuentre la ventana del MessageBox se deben buscar los botones
  • Con base a la ventana del  MessageBox se deben buscar sus ventanas hijas
  • A las ventanas que sean botones se les debe cambiar el texto
  • Dado que el MessageBox es una clase estática, la podemos dar por creada desde un comienzo ( el CLR la creara a la primera referencia que se haga).

Referencias a la API de Windows

Dado que esta tarea requiere de la API de Windows, y de acuerdo a nuestro planteamiento detallado, estas son las funciones de la API que utilizaremos:

  • EnumThreadWindows: Ejecuta un proceso por cada una de las ventanas del hilo actual, según se le indique. Lo usaremos para encontrar cual es la ventana del MessageBox.

  • GetCurrentThreadId: Obtiene el id del Thread en ejecución.

  • GetClassName: Obtiene el nombre de la clase a partir de un handler. Se utilizara junto con EnumThreadWindows para determinar si la ventana procesada es un MessageBox, dado que se desconoce el nombre que tendrán las ventanas del MessageBox, se debe determinar utilizando el ClassName de las ventanas. Más adelante veremos como hallar el ClassName de un MessageBox.

  • EnumChildWindows: Con base al handler de una ventana recorre cada una de sus ventanas hijas y ejecuta un proceso. Solo enumera las ventanas de primer nivel. Lo usaremos para encontrar los botones del MessageBox.

  • SetWindowText: Establece el texto asociado a una ventana, lo usaremos para modificar el texto de los Botones.

 

Diseño

Tenemos una única clase, utilicemos algo sencillo que ilustre el proceso de manera general, con esto bastará.

Diseno

  • Iniciaremos el proceso con EnumThreadWindows al cual le pasaremos un delegado que internamente revisará cada ventana enumerada para determinar si es o no un MessageBox.

  • Sino es un MessageBox revisará la siguiente ventana enumerada hasta que lo encuentre. Sino encuentra es que no hay MessageBox.
  • Cuando encuentra el MessageBox verifica a través de sus ventanas hijas con EnumChildWindows al cual se se pasa un delegado que internamente revisará cada ventana enumerada para determinar si es o no un Botón.

  • Cuando encuentra que es un botón modificará el texto asociado.

 

Implementación

Lo primero que debemos hacer es preparar las funciones a las que accederemos a través de interoperabilidad:

public class MsgBoxUtil
{
    #region Interoperabilidad
    private delegate bool EnumWindowDelegate(IntPtr handler, IntPtr longPointer);
 
    [DllImport("user32.dll")]
    private static extern bool SetWindowText(IntPtr handler, string texto);
 
    [DllImport("user32.dll")]
    private static extern int GetClassName(IntPtr handler, StringBuilder nombre, int tamañoMaximo);
 
    [DllImport("user32.dll")]
    private static extern bool EnumChildWindows(IntPtr handler, EnumWindowDelegate callback, IntPtr longPointer);
 
    [DllImport("user32.dll")]
    private static extern bool EnumThreadWindows(int threadID, EnumWindowDelegate callback, IntPtr longPointer);
 
    [DllImport("kernel32.dll")]
    private static extern int GetCurrentThreadId();
 
    #endregion Interoperabilidad
}

 

No hay nada nuevo en lo que acabamos de ver, son las funciones que hemos mencionado desde el comienzo,  es de destacar únicamente EnumWindowDelegate que es un delegado (puntero a una función) que debemos usar cuando llamemos a EnumChildWindows y a EnumThreadWindows.

 

HackMessageBox

Acto seguido crearemos el método HackMessageBox, el cual recibe como parámetro las cadenas de texto que representan los labels de los botones del MessageBox. Esta función guarda una referencia estática a ese array de textos para poderlos usar en otros lugares de la clase, también se determina si hay o no un windows form y de ser así inicia el procesamiento llamando asíncronamente a EnumThreadWindow, sin embargo no llamaremos directamente a EnumThreadWindows porque requiere demasiados parámetros lo cual nos complica un poco el paso de parámetros en el llamado asíncrono (BeginInvoke), en su lugar llamaremos a BuscaMessageBox que es una función sin parámetros que llamará internamente a EnumThreadWindows con los parámetros necesarios.Dado que BeginInvoque requiere enviar un delegado, debemos definirlo previamente.

 

En el llamado a EnumThreadWindows le debemos pasar el ThreadId el cual obtenemos con un llamado a GetCurrentThreadId, el segundo parámetro es una función ProcesaMessageBoxEnForms que se ejecutará cada por cada ventana que se enumere, el tercer parámetro no lo necesitamos así que será Zero.

private static string[] textoBotones;
    private delegate void BuscarMsgBoxDelegate();
 
    public static void HackMessageBox(params string[] textoBotones)
    {
        MsgBoxUtil.textoBotones = textoBotones;
 
        if (Application.OpenForms.Count > 0)
            Application.OpenForms[0].BeginInvoke(new BuscarMsgBoxDelegate(BuscaMessageBox));
    }
 
    private static void BuscaMessageBox()
    {
        EnumThreadWindows(GetCurrentThreadId(), ProcesaMessageBoxEnForms, IntPtr.Zero);
    }

 

ProcesaMessageBoxEnForms

Revisemos ProcesaMessageBoxEnForms, como esta funcion es llamada por EnumThreadWindows, esta le pasa siempre como parámetro el handler de la ventana que se esta enumerando, así que con ese handler buscaremos el nombre de la clase de la ventana enumerada para así poder compararlo con el nombre de la clase de un MessageBox, sino es un MessageBox entonces se devuelve true y así EnumThreadWindows vuelve a llamar a ProcesaMessageBoxEnForms pero pasando como parámetro la siguiente ventana enumerada, el procedimiento se repite hasta que se logra hallar la ventana del MessageBox. En ese momento se establece la variable indiceTexto en 0, esta variable la utilizaremos para recorrer el array de textos de acuerdo a los botones que encontremos dentro del MessageBox.

Seguidamente llamamos a EnumChildWindows pasándole como parámetro el handle de la ventana que desde luego es el MessageBox que acabamos de encontrar, así que las ventanas que se enumeraran son las subventanas del MessageBox entre ellas… los botones. Como ya encontro el MessageBox y realizo el proceso de busqueda de los botones se retorna false, de tal forma que EnumThreadWindows no siga enumerando ventanas.

private static int indiceTexto;    
    private const string MBOX_CLASSNAME = "#32770";
    private const int STRING_BUILDER_CAPACITY = 256;
    
    private static bool ProcesaMessageBoxEnForms(IntPtr handler, IntPtr longPointer)
    {
        StringBuilder nombreClase = new StringBuilder(STRING_BUILDER_CAPACITY);
        GetClassName(handler, nombreClase, nombreClase.Capacity);
 
        if (nombreClase.ToString() != MBOX_CLASSNAME)
            return true;
        else
        {
            indiceTexto = 0;
            EnumChildWindows(handler, CambiaTextoBotonMessageBox, IntPtr.Zero);
            return false;
        }
    }

 

BREAK> Y de dónde saqué que MBOX_CLASSNAME = “#32770″?

Algunos, o espero que todos los que no sepan se estarán haciendo esa pregunta.

Hay que utilizar herramientas que nos permitan hacer ingeniería inversa, una de estas herramientas es Spy++ que viene incluida con Visual Studio, no haremos un curso completo de Spy++ pero veremos como usarlo para obtener el ClassName de un MessageBox.

  1. Abrir un MessageBox de un programa de .NET Framework
  2. Abrir Spy++
  3. Ahora en Spy++ presionaremos esta tecla Spy

  4. Esto hace que se despliegue el siguiente dialogo:Spy  2

  5. Allí damos click sostenido en la figura señalada en rojo y la arrastramos hasta la ventana del MessageBox, teniendo cuidado de no seleccionar los botones u otras figuras, solo el marco principal. Soltamos el click y damos OK.
  6. Se abre un cuadro de dialogo,vamos a la pestaña Class y allí esta!!! ClassName = #32770.

Spy  3

END BREAK>

CambiaTextoBotonMessageBox

Una vez se ha encontrado el MessageBox se hace el llamado a EnumChildWindows pasándole como parámetro el handler del MessageBox, el segundo parámetro es la función CambiaTextoBotonMessageBox, el tercer parámetro es Zero.

 

EnumChildWindows invoca a CambiaTextoBotonMessageBox por cada una de las ventanas enumeradas, internamente CambiaTextoBotonMessageBox revisa si la ventana procesada es de clase Button, si no lo es entonces se devuelve true para que EnumChildWindow envie la siguiente ventana a proceso, esto continua así hasta encontrar tantos botones como cadenas de texto se hallan enviado en HackMessageBox como parámetro, a cada uno de los botones encontrados se le asigna su cadena de texto en el orden correspondiente.

private const string BUTTON_CLASSNAME = "Button";
 
    private static bool CambiaTextoBotonMessageBox(IntPtr handler, IntPtr longPointer)
    {
        StringBuilder nombreClase = new StringBuilder(STRING_BUILDER_CAPACITY);
        GetClassName(handler, nombreClase, nombreClase.Capacity);
 
        if (nombreClase.ToString() == BUTTON_CLASSNAME && indiceTexto < textoBotones.Length)
        {
            SetWindowText(handler, textoBotones[indiceTexto]);
            indiceTexto++;
        }
        return true;
    }

Ejemplo de uso

Listo ya la funcionalidad esta terminada, pero solo para utilizarla dentro de Windows Forms, ya que si lo tratamos de usar por consola fallará. Sin embargo eso es fácil de solucionar y lo haremos en un próximo artículo. Esta es la manera correcta de utilizarlo.

MsgBoxUtil.HackMessageBox("SI","NO", "CANCELAR");
            MessageBox.Show("hola", "hola", MessageBoxButtons.YesNoCancel);
            
            MsgBoxUtil.HackMessageBox("REINTENTAR", "CANCELAR");
            MessageBox.Show("hola2", "hola2", MessageBoxButtons.RetryCancel);
            
            MsgBoxUtil.HackMessageBox("Descartar", "Reintentar", "Ignorar");
            MessageBox.Show("hola3", "hola3", MessageBoxButtons.AbortRetryIgnore);

 

Les dejo este MessageBox con Botones Personalizados:

MsgBoxUtil.HackMessageBox("Acepto", "Lo Pensare", "Olvidalo");
            MessageBox.Show("hola3", "hola3", MessageBoxButtons.AbortRetryIgnore);

 

MsgBox2

Reversar el MessageBox a su estado original también es posible de hacer, pero lo dejaremos para el próximo artículo, mientras pueden intentarlo si quieren.

 

Cordial saludo a Todos.

Bookmark and Share

« Previous Entries Next Entries »