martes, 28 de agosto de 2012

Reference in the manifest does not match, o la guerra de los manifiestos

En los últimos coletazos de un EXCELENTE AddIn para Excel que hemos desarrollado en mi empresa (TeamPRO), nos hemos puesto a hacer las pruebas de la última versión del código ya con el código publicado y listo para realizar instalaciones.

Y nos ha salido esto:

image

La madre del cordero!!

Después de googlear como locos empezamos a entender lo que ha ocurrido. Para realizar el pintado de los mapas hemos utilizado un proyecto open source (y gratis) llamado CustomColorPicker, el cual hemos añadido a la solución y que compilábamos y hacíamos referencia desde el proyecto en sí del AddIn.

image

Cual es el problema, que el proyecto CustomColorPicker es un proyecto WPF de Windows, y lo que se referencia es un exe. Bueno realmente un exe.deploy. Y este ejecutable tiene un manifiesto que se pega con el manifiesto del AddIn.

¿Cual es la solución? Simple como la vida misma: quítale el manifiesto a CustomColorPicker, o en tu caso a la aplicación que es referenciada por la principal.

¿Cómo se hace eso? Pues mira las pantallitas y te quedará claro.

Primero saca el menú contextual del proyecto al que le quieres quitar el manifiesto con el botón derecho.

image

Así se abrirá la configuración de la aplicación en donde encontramos la configuración que hay que cambiar y que señalo con una flecha y que es “Crear la aplicación sin manifiesto”.

image

Y con esto, compila, publica e instala. Que el mensaje de error por los manifiestos deja de producirse.

Espero que sea de utilidad.

viernes, 24 de agosto de 2012

Mover un Canvas dentro de un Canvas en WPF

Una de las cosas que más agobian es las pequeñas diferencias que hay en los lenguajes de programación de .NET. Y agobian porque las cosas más sencillas no están prácticamente en ningún sitio porque todo el mundo lo da por más que sabido.

Y es una de las razones principales de este blog. Compartir conocimientos de nivel 100 (iniciación).

Así me encuentro, en el proyecto este del Addin para Excel, que tengo la pantalla compuesta por diferentes capas en donde tengo, construidas sobre controles Canvas, los polígonos, los nombres y los diferentes valores.

Algo así, para que se entienda mejor:

   1: <Canvas x:Name="Canvas">
   2:     <Path Name="a114" Fill="#FFC2C2D8" />
   3:     <Path Name="a118" Fill="#FFC2C2D8 />
   4:     <Canvas Name="Valores">
   5:         <TextBlock Canvas.Left="683" Canvas.Top="303" Height="37" Name="t112" />
   6:     </Canvas>
   7:     <Canvas Name="Nombres">
   8:         <TextBlock Canvas.Left="683" Canvas.Top="303" Height="37" Name="t112" />
   9:     </Canvas>
  10: </Canvas>


Tengo un control “Canvas” general sobre el que pinto los polígonos del tipo Path, y añado dos capas más “Valores” y “Nombres” sobre las que pinto textos dentro de controles TextBlock. Viéndose algo tanto que así:


image


Se podría hacer dos mil preguntas de porqué se tomo la decisión técnica de hacer las cosas así, pero eso lo cubriré con un tupido velo.


El problema que quiero solucionar, es que puedo ocultar las cifras del valor que aparecen debajo del nombre y que entonces necesito que el nombre descienda unos 25 pixeles para que quede más centrado verticalmente, ocupando el sitio que ocupa el valor.


Después de darle mil vueltas, y gracias a @pablonete, encontré la forma de hacerlo y que es la mar de sencillo con un método del control del tipo Canvas.



   1: Canvas.SetTop(canvasNombres, 0);

Es decir, Al tipo Canvas le invoco el método SetTop que lo que hace es mover el control tipo Canvas “canvasNombres”  25 pixeles hacia abajo desde su Canvas contenedor. Que ya se encarga el solito de buscarlo.


El quid del asunto aquí es cómo recuperar el Canvas “canvasNombre”. Y que, para darte una pista, es un Child del Canvas principal “Canvas”.


Espero que sea de utilidad.

miércoles, 22 de agosto de 2012

Pintando un gráfico de tartas en un ImageBitMap

 

La verdad que esto del desarrollo sigue siendo muy interesante, aún en mi actual faceta de responsable de departamento y, por ende, con labores más de gestión que de picar código.

Le estoy echando una mano a un equipo que está desarrollando un Addin para Excel, y así pruebo qué tal va el VS2012 RTM, que ha mejorado bastante al ya de por sí bueno VS2012 RC.

Me encuentro que el programador anterior (que el demonio lo tenga en la más miserable celda posible en el infierno) debía tener conocimientos más bien cortitos y, para pintar un indicador que mostrara el porcentaje de un valor, no se le ocurrió otra cosa que hacer un bitmap por cada 10 grados de una imagen de una gráfica de tarta y, con cientos de líneas de código, montar un “chocho” impresionante para saber cual utilizar según el porcentaje.

En cuanto lo vi, me di cuenta que con un poquito de GDI+ lo tenia solucionado. Y así fue, casi mil líneas de código convertidas en los siguientes métodos:

   1: Using System.Drawing;
   2:  
   3: private Image PintarEnImageBitmap(Image imageIndicador, double valorPorcentual)
   4: {
   5:     // Aquí indico que voy a crear un nuevo Bitmap de 50x50px y con un formato ARGB de 32bpp
   6:     Bitmap dibujoDelValor = new Bitmap(50,50,System.Drawing.Imaging.PixelFormat.Format32bppPArgb);
   7:     
   8:     // A continuación creo un nuevo objeto Graphics (sobre el que voy a pintar) a partir del Bitmap anterior
   9:     Graphics graficoDelValor = Graphics.FromImage(dibujoDelValor);
  10:     
  11:     // Declaro el pincel con el que voy a pintar la circunferencia que va a rodear la gráfica de tartaa
  12:     // incluyendo el color y el ancho del pincel        
  13:     System.Drawing.Pen pluma = new System.Drawing.Pen(System.Drawing.Color.White,2);
  14:     
  15:     // Declaro la brocha con la que voy a rellenar la gráfica de tarta
  16:     System.Drawing.SolidBrush brocha = new System.Drawing.SolidBrush(System.Drawing.Color.White);
  17:             
  18:     // Limpio el gráfico con el color negro. Ojo, en Excel el transparente no vá bien.
  19:     graficoDelValor.Clear(System.Drawing.Color.Black);
  20:  
  21:     // Le indico el grado de aliasing que quiero utilizar al dibujar
  22:     graficoDelValor.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
  23:     
  24:     // Pinto la circunferencia que rodea a la gráfica de tarta
  25:     graficoDelValor.DrawEllipse(pluma, 0, 0, 47, 47);
  26:  
  27:     // Pinto la gráfica de tarta. Invoco a un método que me transforma el valorPorcentual a grados.
  28:     // 270 es para que empiece a pintar desde una linea vertical. Ya que 0 es la horizontal derecha.
  29:     graficoDelValor.FillPie(brocha, 0, 0, 47, 47, 270, PorcentajeAGrados(valorPorcentual));
  30:  
  31:     // Cargo el Bitmap resultante en un objeto Image
  32:     imageIndicador.Source = BitmapToSourceImage(dibujoDelValor);
  33:  
  34:     Return imageIndicador;
  35: }

El método PorcentajeAGrados, no puede ser más sencillo:



   1: private int PorcentajeAGrados(double valorPorcentual)
   2: {
   3:     return (int)(valorPorcentual * 3.6);
   4: }

Y el “truco del almendruco” es pasar el Bitmap GDI+ a un tipo ImageSource, que es el que puede leer los ImageBitmap de DirectX (y que por alguna extraña causa, el programador anterior prefirió utilizar en vez de los Bitmap GDI+).


Para ello, copio y pego el código que me he encontrando googleando, y que como no me lo he apuntado no lo puedo referenciar como debería hacer.



   1: /// <summary>
   2: /// Dado un objeto Bitmap lo convierte en un objeto ImageSource
   3: /// </summary>
   4: /// <param name="dibujoDelValor"></param>
   5: /// <returns></returns>
   6: private System.Windows.Media.ImageSource BitmapToSourceImage(System.Drawing.Bitmap dibujoDelValor)
   7: {
   8:     System.IO.MemoryStream ms = new System.IO.MemoryStream();
   9:     dibujoDelValor.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
  10:     System.Windows.Media.Imaging.BitmapImage bImg = new System.Windows.Media.Imaging.BitmapImage();
  11:     bImg.BeginInit();
  12:     bImg.StreamSource = new System.IO.MemoryStream(ms.ToArray());
  13:     bImg.EndInit();
  14:  
  15:     return bImg;
  16: }

Por lo cual, y resumiendo. Una llamada de ejemplo sería:



   1: Image imagenIndicador = new Image();
   2: imagenIndicador = PintarEnImageBitmap(imagenIndicador, 73);

Y el resultado, en el caso de la aplicación que estamos realizando es algo así:


image


Según me ha comentado Rodrigo, debería de investigar el no tener que hacer lo que estoy haciendo que es pintar en GDI+ y después utilizar objetos de DirectX, si no que debería pintar directamente con la propia API de Excel… pero eso es para nota.






Espero que sea de utilidad.