Modificar y borrar datos XML

30. October 2009 21:50 by Oscar.SS in XML  //  Tags:   //   Comments (2)

En los artículos anteriores vimos como leer, escribir e insertar datos en un archivo XML. Aquí veremos como modificar (o remplazar) y borrar un nodo de nuestro XML.

De esta forma quedan cubiertas todas las acciones que se pueden realizar sobre nuestros registros en documentos XML. Recordaros como siempre que el código hace referencia al archivo XML que utilizamos en el primer artículo de esta serie.

El código que aquí veremos se puede utilizar tanto para modicar un nodo como para borrarlo, tan solo con una leve diferencia. Cuando sea el momento, veremos en que consiste esta pequeña diferencia.

Pasemos a las explicaciones. Los objetos XmlDocument, XmlElement y XmlNode disponen de dos métodos que nos permitirán realizar la modificación y la eliminación del nodo deseado. Estos métodos son:

  • ReplaceChild(nodoNew, nodoOld). Reemplaza el nodo existente por el nodo con los nuevos datos.
  • RemoveChild(nodoOld). Elimina un nodo permanentemente.

Estos métodos actuan sobre los nodos secundarios del objeto que realiza la llamada. Por lo tanto, el "truco" consiste en posicionarse en el árbol del XML sobre el nodo padre del nodo que pretendemos actualizar, reemplazar o borrar.

El código que a continuación veremos hace uso del método secundario CrearNodoXml() que ya vimos en al artículo "Insertar datos XML". Recordar que este método devuelve un objeto XmlNode de tipo "empleado" devidamente construido.

public void ModificarDatosXml(string id, string nom, string ape, string nss, string fijo, string mvl)
        {
            
//Cargamos el documento XML.
            
documento = new XmlDocument();
            
documento.Load(Ruta);

            
//Obtenemos el nodo raiz del documento.
            
XmlElement empleados documento.DocumentElement;

            
//Obtenemos la lista de todos los empleados.
            
XmlNodeList listaEmpleados documento.SelectNodes("empleados/empleado");

            foreach 
(XmlNode item in listaEmpleados)
            {
                
//Determinamos el nodo a modificar por medio del id de empleado.
                
if (item.FirstChild.InnerText == id)
                {
                    
//Nodo sustituido.
                    
XmlNode nodoOld item;

                    
//Nodo nuevo.
                    
XmlNode nodoNew CrearNodoXml(id, nom, ape, nss, fijo, mvl);

                    
//Remplazamos el nodo.
                    
empleados.ReplaceChild(nodoNew, nodoOld);

                    
//Borrar un nodo.
                    //empleados.RemoveChild(nodoOld);
                
}
            }

            
//Salvamos el documento.
            
documento.Save(Ruta);
        
}

AJAX en ASP.NET 2.0 con Script CallBacks

23. October 2009 22:14 by Oscar.SS in Desarrollo Web  //  Tags:   //   Comments (2)

Con la llegada de ASP.NET 2.0 se puso a nuestra disposición otra técnica para realizar llamadas en segundo plano desde el cliente. Esta técnica es denominada Script CallBacks. La ventaja más notable de esta forma de implementar AJAX es que nos evita tener que escribir tanto código cliente. En concreto, nos evita tener que escribir todo el código JavaScript para crear, configurar y enviar los datos al servidor con XMLHTTPRequest, tal y como vimos en el post anterior. Naturalmente si tendremos que utilizar código cliente para manipular los datos una vez devueltos por el servidor.

Comencemos recordando la interfaz de usuario que teníamos en el ejemplo anterior.

  

 

Código Servidor

Antes de nada, debemos saber que la técnica de Script CallBacks se apoya en la interfaz ICallbackEventHandler. Por lo tanto debemos implementar esta interfaz en la página que recibe la llamada asíncrona. Más tarde veremos cuales son los métodos de esta interfaz.

Ya hemos comentado antes que no necesitamos escribir todo el JavaScript a mano para enviar los datos asíncronamente al servidor. Pero entoces...¿como enviamos los datos?. En realidad, desde el cliente si llamaremos e inviaremos los datos al servidor pero todo esto lo configuraremos desde el propio servidor. Veamos como.

         this.listaNombres.Attributes["onchange"ObtenerFuncionCliente();

En primer lugar, asignamos al evento onchange de la lista de nombres una cadena que será devuelta por la función ObtenerFuncionCliente(). Esta cadena contiene el nombre de una función JavaScript proporcionada por ASP.NET. Esta función cliente será la encargada de realizar la llamada asíncrona y de enviar los datos al servidor. La función toma la forma siguiente:

 

WebForm_DoCallback("Control", "DatosEnviados", "FuncionRecogerDatos", "idLlamada", "FuncionRecogerErrores", "Asíncrono")

 

  • Control (string). Nombre del control que implementa la interfaz ICallbackEventHandler.
  • DatosEnviados (string). Cadena con los datos enviados desde el cliente al servidor.
  • FuncionRecogerDatos (string). Nombre de la función cliente que será la encargada de recoger y manipular debidamente los datos recibidos desde el servidor.
  • idLlamada (string). Parámetro opcional, un identificador único de esta llamada. Sirve para diferenciarla de otras llamadas en contextos de llamadas múltiples. Puede ser null.
  • FuncionRecogerErrores (string). Nombre de la función cliente encargada de recoger y manipular los errores producidos.
  • Asíncrono (bool). Determina si la llamada será realizada de forma asíncrona o no.
Pero como ya hemos comentado, esta función de JavaScript y todos sus parámetros serán configurados con código servidor.
  
    private string ObtenerFuncionCliente()
    {
        
//Obtener los parámetros de la función cliente.
        
var control = this;

        string 
datoRecibido = string.Format("document.getElementById('{0}').value"this.listaNombres.ClientID);
        
        string 
FuncionCliente "RecogerRespuestaCallBack";

        string 
idLlamada "null";

        string 
FuncionClienteError "MostrarError";

        bool 
llamadaAsincrona = true;

        
//Configurar la función cliente con los parámetros anteriores.
        
string funcionConfigurada Page.ClientScript.GetCallbackEventReference(
            control, datoRecibido, FuncionCliente, idLlamada, FuncionClienteError, llamadaAsincrona)
;

        
//Devolvemos la instrución JavaScript con el nombre de la función que realiza la llamada.
        
return string.Format("javascript:{0}", funcionConfigurada);
    
}

El método GetCallbackEventReferecen() devuelve una referencia a la función cliente WebForm_DoCallback() que hemos comentado antes. Entendamos lo que hemos hecho hasta ahora.

En la primera petición a nuestra página, esta devolverá entre todo el código HTML un fragmento de JavaScript con la función WebForm_DoCallback() y todos sus parámetros. Esta función sera la encargada de enviar los datos al servidor cuando se produzca el evento onchange.

 

La interfaz ICallbackEventHandler implementa únicamente dos métodos: 

  • RaiseCallbackEnvent(). Esta función será llamada automaticamente cuando se reciba una llamada en segundo plano desde el cliente.
  • GetCallbackResult(). Devuelve una cadena con los datos y llama automaticamente a la función JavaScript encargada de recoger los datos en el cliente.

    public void RaiseCallbackEvent(string datosCliente)
    {
        datoRecibido 
datosCliente;
    
}

    
public string GetCallbackResult()
    {
        
string rutaDatos Server.MapPath("~/App_Data/datos.xml");

        
//Antes de enviar la petición simulamos una tarea larga.
        
System.Threading.Thread.Sleep(5000);

        return 
ManejarDatos.ObtenerRespuesta(datoRecibido, rutaDatos);
    
}

Código Ciente
Poco queda por decir. Ahora solo tendremos que implementar las dos funciones Java Script que especificamos al configurar los parámetros del método GetCallbackEventReferecen(). Una función para recoger y mostrar los datos al usuario y otra para el control de los posibles errores que se produzcan.
//Funcion que es llamada automaticamente para procesar la respuesta del servidor.
function RecogerRespuestaCallBack(xmlReturn, idLlamada) {
    
try {
       
//CargarXmlString() parsea una cadena en un documento XML.
        
var datosReturn CargarXmlString(xmlReturn).getElementsByTagName("categoria");
        
var resp document.getElementById("txRespuesta");
        
resp.innerText datosReturn[0].childNodes[0].nodeValue;
    
}
    
catch (ex) {
        MostrarError(ex)
;
    
}

}


//Funcion llamada automaticamente cuando se produce un error.
function MostrarError(ex) {
    alert(
"Error: " + ex);
}

 

Código de descarga 

El código completo mencionado en este artículo se encuentra en la carpeta AJAX_NET_2.0 del siquiente enlace. Para probar la aplicación ejecutar la página AJAX_ScriptCallBacks.aspx de la carpeta mencionada.

AJAX_ASP.NET.rar (15,45 kb)

AJAX en ASP.NET 1.0 con XMLHTTPRequest

18. October 2009 15:51 by Oscar.SS in Desarrollo Web  //  Tags:   //   Comments (2)

Este es el primero de una serie de artículos que escribiré sobre la implementación de un mismo ejemplo de AJAX en las diferentes versiones del framework.

Cuando veamos el ejemplo de AJAX con .NET Framework 3.5, podremos observar que todo esta muy encapsulado y aunque es muy intuitivo y productivo nos aleja bastante de lo que ocurre "por debajo".

Esto tiene dos consecuencias negativas, que tenemos menos control y que los programadores noveles, que comienzan sus primeros pasos directamente en la ultima versión de la plataforma no comprenden como funcionan conjuntamente estas tecnologías. Precisamente este es el motivo que impulsa esta serie de artículos.

¡Comencemos ya!. En primer lugar veamos la interfaz de usuario y expliquemos que pretendemos hacer. Recuerdo que el ejemplo será el mismo en todos los artículos de la serie pero implementados de forma diferente.

 


La aplicación es muy simple. El usuario selecciona un nombre de empleado y se devuelve por AJAX la categoría profesional del mismo. Estos datos están guardados en el servidor en un archivo XML. En el servidor, se ha relentizado la devolución de los datos para simular una tarea muy larga a la hora de obtener los datos.
 
El campo de texto inferior solo sirve para comprobar como a pesar de que se esta realizando una petición al servidor, el usuario puede seguir interactuando con la IU escribiendo al tiempo que los datos vuelven desde el servidor.
 
 
Código Cliente
El código cliente consiste en crear un objeto de tipo XMLHTTPRequest, configurarlo y enviar los datos al servidor. También implementaremos una función para recoger los datos devueltos por el servidor y mostrar el resultado. Mencionar que este código, al ser solo JavaScript, es compatible con cualquier plataforma, ya sea PHP, Java o .NET como en este caso.
Esta es la función que envía los datos al servidor.
function EnviarPeticion(datoEnviado) {

    
//Crear transmisor
    
try {
        transmisor 
= new ActiveXObject('Msxml2.XMLHTTP');
    
}
    
catch (ex1) {
        
try {
            transmisor 
= new ActiveXObject('Microsoft.XMLHTTP')//Inferior a IE7.
        
}
        
catch (ex2) {
            
try {
                transmisor 
= new XMLHttpRequest()//IE7, Mozilla FireFox, etc.
            
}
            
catch (ex3) {
                transmisor 
= false;
            
}
        }
    }

    
//Configurar el transmisor y enviar los datos.
    
if (transmisor != null) {
        transmisor.onreadystatechange 
RecogerRespuesta;

        
//Envio de datos con POST.
        
transmisor.open("POST""AJAX_XMLHTTPRequest.aspx"true);
        
transmisor.setRequestHeader("Content-Type""application/x-www-form-urlencoded");
        
transmisor.send("opcion=" + datoEnviado);  // param1=valor&param2=valor
    
}
}

En primer lugar creamos un objeto transmisor de tipo XMLHTTPRequest que nos permitirá comunicarnos con el servidor. Este objeto tiene diferentes implementaciones dependiendo del tipo de navegador cliente.

A continuación configuramos el transmisor para enviar los datos. La propiedad onreadystatechange determina cual será la función a la que se llamará automaticamente cuando los datos estén de vuelta desde el servidor.

La función open() abre la conexión con los siguientes parámetros, todos de tipo cadena menos un boleano:

  • POST/GET: método de envío del protocolo HTTP.
  • Página de servidor a la que se envía la petición. Es recomendable que esta página no contenga código HTML. Solo la declaración de la directiva @Page.
  • True/False (bool): Realizar una llamada asíncrona (true) o una llamada no asíncrona (false).
  • Usuario: Nombre de usuario. Este parámetro y el siguiente solo es necesario para páginas con autentificación de usuarios.
  • Contraseña: Contraseña del usuario. Opcional.
La función setRequestHeader() solamente es necesario si estamos enviando la petición por el método POST. Se encarga de especificar los atributos necesarios en la cabecera de la petición HTTP.
La función send() envía los datos al servidor en formato cadena. La cadena formada debe tener la forma param1=valor&param2=valor&param3=valor etc.
Con esto hemos realizado una llamada asíncrona hacia el servidor. Allí, lo veremos a continuación, se recogerá los datos enviados por el cliente, se manipularan debidamente y de devolverán al cliente. Concretamente a la función cliente especificada en la propiedad onreadystatechange.
function RecogerRespuesta() {
    
if (transmisor.readyState == 4)    // 4 = completado
    
{
        
if (transmisor.status == 200)    // 200 = OK
        
{
            
var datosReturn transmisor.responseXML.getElementsByTagName("categoria");
            var 
resp = document.getElementById("txRespuesta");
            
resp.innerText datosReturn[0].childNodes[0].nodeValue;
        
}
        
else //En caso de error
        
{
            
alert("Error: " + transmisor.status + " / " + transmisor.statusText);
        
}
    }
}

Primero comprobamos que la petición a finalizado con la propiedad readyState y a continuación comprobamos que no se han producido errores con la propiedad status.

Con la propiedad responseXML recogemos los datos como un documento XML dado que así han sido enviados desde el servidor. También pueden ser recogidos como una cadena con la propiedad responseText en el caso de que solo se enviará desde el servidor una cadena.

Accedemos al nodo que nos interesa del documento XML con la función getElementByTagName() y utilizando el DOM lo mostramos por pantalla.

 

Código Servidor 

El código cliente consiste básicamente en recoger los datos con el objeto Request, leer el archivo XML y buscar en el dato requerido. Construir luego un XML con el dato requerido y devolverlo al cliente con el método Response.Write().

Este es un ejemplo del código que se ejecutará en el evento Load() de la página.

        //Recogemos el dato enviado desde el cliente.
        
string datoRecibido Request.Params["opcion"];

        
// Se devuelve como XML.
        
Response.ContentType "text/xml";
        
// Evitar que haya caché.
        
Response.AppendHeader("cache-control""no-cache");
        
Response.Expires -1;

        
//Antes de enviar la petición simulamos una tarea larga.
        
System.Threading.Thread.Sleep(5000);

        
//Enviamos y cerramos la respuesta.
        
Response.Write(ManejarDatos.ObtenerRespuesta(datoRecibido, rutaDatos));
        
Response.End();

No hay mucho que comentar. Indicar que ManejarDatos es una clase con métodos estáticos que encapsula toda la funcionalidad para recuperar el dato requerido desde el XML en el servidor y con este dato construir el XML  que será devuelto al cliente.

 

Código de descarga 

El código completo mencionado en este artículo se encuentra en la carpeta AJAX_NET_1.x del siquiente enlace. Para probar la aplicación ejecutar la página index.htm de la carpeta mencionada.

AJAX_ASP.NET.rar (15,45 kb)

Bing vs Google

13. October 2009 01:05 by Oscar.SS in Herramientas, Personal, Internet  //  Tags: , ,   //   Comments (0)

Mi intención al escribir este artículo es responder a dos preguntas muy sencillas y directas. ¿Porqué no utilizar Google? y ¿porqué no utilizar Bing?. Teniendo siempre en cuenta que todo lo aquí expresado solo es la humilde opinión de uno mismo.

 

¿Porque no utilizar Google?

Las razones para no utilizar Google no pueden ser técnicas, dado que este buscador ha demostrado muy sobradamente que es una eficaz herramienta de trabajo. Los motivos para dejar de darle cuota de mercado a esta empresa, en cuanto a búsquedas se refiere, son más de tipo filosófico o ético.

Si habéis mirado el enlace anterior, rápidamente se pueden comprender las escalofriantes cifras que alcanza este buscador.

 

 

Precisamente estas cifras son el motivo para dejar de utilizar un poco este buscador. No se puede permitir que toda (o la gran mayoría) de la información del mundo pase por una sola empresa privada, publica o gobierno.

Daros cuenta, que toda la información sobre nuestros gustos de lectura, películas, deportes, compras, bancos, entretenimiento y un largo etc, pasan practicamente por una sola empresa. Creo que este tipo de monopolios es muy peligroso o por lo menos preocupante.

¿Que hacen con esta información?. Supongo, que por una parte las costumbres de búsquedas de todos los usuarios se utilizan para mejorar el buscador. Y están en su pleno derecho de hacerlo.

¿Pero quién nos asegura que no se utilicen con otros fines?. De alguna forma, podemos hablar de información privilegiada. ¿Podría usarse con fines fraudulentos?. No lo sé, pero si es posible, seguro que el ser humano encuentra la forma de aprovecharse de ello. ¡Siempre lo hace!.

Películas a parte, a mí si me preocupa que este poder lo tenga una sola empresa privada.

 

¿Porque no utilizar Bing?

Lamentablemente los motivos para no usar Bing si pueden ser técnicos. He estado usando este buscador en mi casa, cuando no tengo prisa y cuando las búsquedas no son importantes o son muy evidentes. En cambio, en el trabajo sigo usando Google y ahora veréis porque.

Si introducís la siguiente cadena de búsqueda: sys.WebForm.PageRequestManager 

En Google obtenemos 23.600 posibles resultados. Y lo que yo buscaba se encontraba en 4º lugar.

En Bing obtenemos solo 2 posibles resultados. Y ninguno de los dos se acerca a la información requerida. Ademas, una página esta en idioma italiano y la otra oriental.

¿Porque hay una deferencia tan obvia?. La razón es porque escribí mal la cadena de búsqueda. Debería haber escrito: sys.WebForms.PageRequestManager

¿Ven la diferencia?...¿no?...¡¡Bing tampoco!!. La diferencia es una simple s en la palabra Forms.

Sin embargo, con la cadena correctamente escrita, Bing da resultados muy buenos desde las primeras posiciones. Pero si no le dices exactamente que tiene que buscar, se encuentra perdido. La verdad es, que he encontrado muchas búsquedas en las que Google daba mejores resultados. Pondré más ejemplos en el futuro y esta vez sin trampas.

En defensa de Bing, quizás podría decirse que es un buscador más joven. Si bien es cierto que hereda de Windows Live Search y MSN Search, también es cierto que aún no tiene el historial que pueda tener Google. Y una parte de la eficacia de los buscadores se encuentra en el historial de búsquedas con éxito, indexación, y algoritmos de inteligencia artificial que les permiten aprender de todas las búsquedas.

En fin, que yo seguiré usando Google en el kurro por ser más eficaz de momento y usaré Bing en casa para ayudar a repartir un poco la cuota de mercado.

Si queréis investigar para tener vuestro propio criterio aquí tenéis una herramienta que permite comparar simultaneamente ambos buscadores.

 

Interoperabilidad de Microsoft Office Project en .NET

4. October 2009 11:24 by Oscar.SS in Desarrollo Office  //  Tags:   //   Comments (0)

En las últimas semanas en el trabajo he tenido que pelearme con una librería que en mí humilde opinión no es muy amigable de utilizar y por desgracia no existe apenas documentación y la que existe es muy pobre. Se trata de importar y exportar datos de las planificaciones de proyectos desde nuestras aplicaciones a Microsoft Office Project y viceversa.

En Visual Studio 2008 ya existen tipos de proyectos para interoperabilidad con Office pero si estáis trabando en el Framework 1.x  tendréis que descargaros un paquete de instalación que contiene las DLLs para la interoperabilidad con Microsoft Office 2003.

http://www.microsoft.com/downloads/details.aspx?familyid=3c9a983a-ac14-4125-8ba0-d36d67e0f4ad&displaylang=en

Para ver las especificaciones, instrucciones de instalación y demás información ojear este enlace:

http://msdn.microsoft.com/en-us/library/aa188781(office.10).aspx

 

Una vez instaladas las DLLs deberéis de añadir en vuestro proyecto referencias al  siguiente componente:

Ahora dejo algunos ejemplos de código con comentarios en cada linea. ¡Espero que os sirva de ayuda!. 

 

//Crear una aplicación de tipo Project para EXPORTAR datos desde nuestra aplicación.
ApplicationClass Aplicacion = new ApplicationClass();
 
//Aplicacion.AppMaximize(); --> Opcional
 
//Abrir la aplicación.
Aplicacion.FileNew(Missing.Value, Missing.Value, Missing.Value, Missing.Value);
 
//Crear un archivo project.
Project Proyecto = Aplicacion.ActiveProject;
 
//Cambiar el calendario para que los fines de semana sean laborable.
Aplicacion.BaseCalendarEditDays("Estándar", Missing.Value, Missing.Value, PjWeekday.pjFriday, true, Missing.Value, Missing.Value,
"Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value);
 
Aplicacion.BaseCalendarEditDays("Estándar", Missing.Value, Missing.Value, PjWeekday.pjMonday, true, Missing.Value, Missing.Value,
"Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, 
Missing.Value, Missing.Value);
 
Aplicacion.BaseCalendarEditDays("Estándar", Missing.Value, Missing.Value, PjWeekday.pjSaturday, true, Missing.Value, Missing.Value,
"Missing.Value, Missing.Value,Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,
Missing.Value, Missing.Value);
 
Aplicacion.BaseCalendarEditDays("Estándar", Missing.Value, Missing.Value, PjWeekday.pjSunday, true, Missing.Value, Missing.Value,
"Missing.Value, Missing.Value,Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, 
Missing.Value, Missing.Value);
 
Aplicacion.BaseCalendarEditDays("Estándar", Missing.Value, Missing.Value, PjWeekday.pjThursday, true, Missing.Value, Missing.Value,
"Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, 
Missing.Value, Missing.Value);
 
Aplicacion.BaseCalendarEditDays("Estándar", Missing.Value, Missing.Value, PjWeekday.pjTuesday, true, Missing.Value, Missing.Value,
"Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, 
Missing.Value, Missing.Value);
 
Aplicacion.BaseCalendarEditDays("Estándar", Missing.Value, Missing.Value, PjWeekday.pjWednesday, true, Missing.Value, Missing.Value, 
Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value, 
Missing.Value, Missing.Value);"
 
//Añadir las tareas.
//Las tareas pueden tener a su vez subTareas y estas deben ser declaradas antes.
//subLine = Linea después de la que se quiere insertar la subTarea.
Task subTarea = Proyecto.Tasks.Add("NombreSubTarea", subLine);
subTarea.Start = "10/10/2009";
subTarea.Finish = "12/10/2009";
subTarea.AppendNotes("Nota adjunta a la subTarea");
 
//Añadimos los recursos asignadas a subTarea.
Resource recurso = Proyecto.Resources.Add("NombreRecurso", subLine);
subTarea.Assignments.Add(subTarea.ID, recurso.ID, obj.ocupacion);
 
Task subTarea2 = Proyecto.Tasks.Add("NombreSubTarea2", subLine + 1);
subTarea2.Start = "12/10/2009";
subTarea2.Finish = "14/10/2009";
subTarea2.AppendNotes("Nota adjunta a la subTarea2");
 
//Añadimos la tarea padre.
//line = Linea después de la que se quiere insertar la subTarea.
Task tareaPadre = Proyecto.Tasks.Add("NombreTareaPadre", line);
tareaPadre.Start = "10/10/2009";
tareaPadre.Finish = "14/10/2009";
tareaPadre.AppendNotes("Nota adjunta a la Tarea");
 
//Indicar cuales son las tareas hijo de tareaPadre;
subTarea.OutlineIndent();
subTarea2.OutlineIndent();
 
//Añadir diagrama de Gantt.
Aplicacion.GanttBarFormat(tareaPadre.ID, Missing.Value, Missing.Value, Missing.Value, Missing.Value, Missing.Value,Missing.Value, 
Microsoft.Office.Interop.MSProject.PjColor.pjGreen, Missing.Value, Missing.Value,Missing.Value, Missing.Value, Missing.Value, 
Missing.Value, Missing.Value, Missing.Value,Missing.Value, Missing.Value);
 
//Salvar y Cerrar los recuersos abiertos.
Proyecto.SaveAs(ruta, Microsoft.Office.Interop.MSProject.PjFileFormat.pjMPP, Type.Missing, Type.Missing, Type.Missing,Type.Missing,
 Type.Missing, Type.Missing, Type.Missing, "MSProject.mpp.9", Type.Missing, Type.Missing,Type.Missing, Type.Missing, Type.Missing);
 
//Si estamos IMPORTANDO datos deberemos sustituir la instrución anterior por...
//Aplicacion.FileClose(Microsoft.Office.Interop.MSProject.PjSaveType.pjDoNotSave, true);
 
//Cerrar la aplicación.
Aplicacion.Quit(Microsoft.Office.Interop.MSProject.PjSaveType.pjDoNotSave);
 

Recent Comments

Comment RSS

Month List