Window propietari Form, Form propietari Window

Quan es treballa amb WPF es poden utilitzar les antigues WinForms sense cap problema. Però com ho podem fer per assignar com a propietari d’una finestra window un winform i viceversa? El concepte és utilitzat sense problemes entre objectes de la mateixa classe i assignar propietaris ens és útil per assegurar-nos de que la finestra es tancarà en el moment que es tanqui la principal, és a dir, la responsable de haver obert l’altre.

Detallo a continuació com fer per cada un dels casos.

Un WinForm obre un Window

És dels dos el més senzill. Es tracta d’utilitzar el WindowInteropHelper que es troba dins l’espai de noms System.Window.Interop. Creem una instància de la classe passant per paràmetre la instància de la Window que volem obrir.

Window1 w = new Window1();
System.Windows.Interop.WindowInteropHelper ih=new System.Windows.Interop.WindowInteropHelper(w);

La propietat Owner de la instància WindowInteropHelper i assignem la propietat Handle del WinForms
ih.Owner = Handle;

A partir d’aquest moment ja podem obrir la window
w.Show();

Un Window obre un WinForm

Per mi és el que menys m’agrada però és efectiu i sembla que la única manera de poder-ho fer.
Necessitem utilitzar un mètode de la llibreria User32.dll directament.

[DllImport("user32.dll")]
private static extern int SetWindowLong(HandleRef hWnd, int nIndex, int dwNewLong);

Després podem obrir el WinForm

Form1 f = new Form1();
WindowInteropHelper helper = new WindowInteropHelper(this);
SetWindowLong(new HandleRef(f, f.Handle), -8, helper.Handle.ToInt32());
f.Show();

WPF, ASP.NET Web Forms, ASP.NET MVC

M’agrada el que faig perquè em permet conèixer les tecnologies que hi ha a .Net i sobretot perquè m’obliga estar al dia. Però aquesta setmana es dóna la casualitat que estic impartint cursos de WPF, ASP.NET Web forms i ASP.NET MVC. Alguns son amb C# i altres amb VB.NET.

Avui mateix tot explicant les col·leccions genèriques amb Vb.net no m’he adonat fins al cap d’una estona que ho estava explicant amb C#. Ja sé que en el fons és el mateix, però els programadors son de Vb.net i ells volen aplicar-ho.

 

Compartir una master page

Un dels problemes que ens podem trobar quan tenim moltes aplicacions web a una mateixa empresa és la de tenir que utilitzar en totes elles la mateixa master page. Aquí surt la necessitat de compartir una master page a totes les aplicacions web.

La manera de fer-ho és fàcil el que passa és que s’ha d’explicar bé. Us passo un link on s’explica molt bé els passos que hem de fer i que jo personalment he provat i funciona:
http://weblogs.asp.net/dwahlin/archive/2005/11/16/430779.aspx

Bàsicament es tracta de crear un Web Site (no, un Web Application no funciona) on afegim una MasterPage. El nom d’aquesta és la que surt per defecte. Però de totes maneres és indiferent.

Publiquem el web site amb la particularitat de NO tenir seleccionat la opció de “Permitir que este sitio precompilado se actualice”, SI seleccionar “Utilizar nomenclatura fija y ensamblados de una sola página”. Firma si vols instal·lar a la GAC, si no no ho fagis.

a) Si has firmat instal·la la dll al Gac amb gacutil

b) Si no has firmat copia la dll a a la carpeta bin\debug o bin\release de l’aplicació web.

Si treballes amb Web Sites millor instal·la a la GAC ja que sinó és més complicat.

Continuo amb el supòsit de que hem firmat i hem instal·lat a la gac.

Crea una aplicació web o un web site, el que tu vulguis, i en el web.config posa:

<compilation debug=”false” targetFramework=”4.0″>
<assemblies>
<add assembly=”App_Web_masterpage.master.cdcab7d2, Version=0.0.0.0, Culture=neutral”/>
</assemblies>
</compilation>

Crea una master page i borres el code behind i borres tot el contingut de disseny que només quedi:

<%@ Master Language=”C#” AutoEventWireup=”true” Inherits=”ASP.masterpage_master” %>

Crea ara una pàgina contingut que utilitzi aquesta master page i ja està.

Si tens més d’una master page s’ha de repetir el procés per cada una ja que tenium una dll diferent.

Sqldatasource no et dóna la consulta final

No no t’ho diu. Aquesta és la conclusió que he arribat després de buscar i buscar la manera per poder saber quina és la consulta SQL final amb els paràmetres substituïts que es fa a la base de dades. Aquest pot semblar un fet absurd però té la seva lògica quan les sentències SQL que volem executar son d’una mida considerable, de moltes joins, de molts filtres,… acabem tenint una consulta SQL dificil de interpretar per Debug i que a sobre parametritzada no podem saber com és realment.

De totes maneres el món de la programació no té límits, tenim dues maneres de poder-ho saber:

  • Contruïm una funció que reconstrueixi el SelectCommand substituint nosaltres els paràmetres per els valors que trobem a la llista SelectParameters
  • Utilitzem SQL Profile que fa un trace de les consultes que arriben a la base de dades

És així, no hi ha més oi? saps tu la manera?

Més d’un sitemap a la web

web.sitemap és el nom del fitxer que per defecte es crea en una aplicació web d’asp.net on podem detallar l’estructura d’aquesta, possibilitant així la utilització del SiteMapPath i el Menu. Dos controls web molt útils que ens mostra el camí que hi ha entre la home i la pàgina que estem visitant el primer i la creació automàtica d’un menú de tota la web el segon.

Però algunes vegades és necessari especificar més d’un sitemap sobretot en el cas que tinguem apartats a la nostra web que canvien completament el menú. També es podria donar el cas de voler donar un menú diferent segons l’usuari que ens visita.

Per aconseguir-ho el que primer hem de fer és afegir a la nostra aplicació tants web.sitemap com necessitem aplicant un nom diferent a cada un clar.

Des del web.config hem de configurar els diferents site maps com a proveïdors diferents.
<siteMap>
<providers>
<add name="CustomSiteMap" type="System.Web.XmlSiteMapProvider" siteMapFile="~/CustomWeb.sitemap"/>
<add name="MinimalSiteMap" type="System.Web.XmlSiteMapProvider" siteMapFile="~/MinimalWeb.sitemap"/>
</providers>
</siteMap>

Al SiteMapDatasource i Sitemappath indiquem a la propietat provider el nom que hem definit al web.config.

Sitemapdatasource1.Provider="MinimalSiteMap"
Sitemappath1.Provider="MinimalSiteMap"

Xml i Databinding anidats en ASP.NET

Algunes vegades quan estem enllaçant a documents Xml amb un XmlDataSource ens podem trobar amb la necessitat de recórrer nodes inferiors al node que estem enllaçat. És en aquest moment quan podem utilitzar un control Repeater per recórrer aquest nou arbre d’elements. Per fer això no és necessari afegir cap DataSource ni programar cap línia de codi.

Imagina un document Xml amb una estructura:

<item atr="A">
<subitem subatr="1"></subitem>
<subitem subatr="2"></subitem>
</item>

Des de la pàgina web posem un ListView per recórrer els primers elements

<listview DataSourceID="xmldatasource1">
<itemtemplate>
<asp:label text='<%# Eval("atr") %>'></asp:label>
</itemtemplate>
</listview>

Dins del ListView posem un Repeater per recórrer els segons elements

<listview DataSourceID="xmldatasource1">
<itemtemplate>
<asp:label text='<%# Eval("atr") %>'></asp:label>
<div>
<asp:Repeater>
<itemtemplate>
<asp:label text='<%# Eval("subatr") %>'></asp:label>
</itemtemplate>
</asp:Repeater>
</div>
</itemtemplate>
</listview>

Per tal de que el Repeater funcioni necessitem assignar a la propietat DataSource l’expressió de Databinding XPathSelect.

<asp:Repeater Datasource='<%# XPathSelect("subitem") %>'>
<itemtemplate>
<asp:label text='<%# Eval("subatr") %>'></asp:label>
</itemtemplate>
</asp:Repeater>

cscript error: can’t find script engine for script .js

En un dels meus projectes, que aviat us parlaré, es crea un msi amb la particularitat de que s’afegeix un check box a la última pantalla de l’instal·lable per poder demanar a l’usuari si es vol o no executar l’aplicació que s’acaba d’instal·lar. La manera per fer-ho es troba en aquest link i funciona molt bé: Run exe after msi installation

Fins ara no tenia cap problema, porto ja publicades unes quantes versions i sempre s’ha construït i modificat l’msi sense problemes. Fins avui, el meu msi no es podia crear perquè el Visual Studio em donava el següent error:

‘PostBuildEvent’ failed with error code ‘1’ ‘Unspecified error’

A la pantalla output es veu:

cscript error: can’t find script engine for script .js

La única cosa que ha canviat ha sigut la instal·lació del Visual Studio 2010 SP1. Pensant què podia ser i buscant per internet alguna solució al final he donat amb la resposta.

Tal i com ens parla el link que us he deixat per aconseguir el checkbox cal des del Setup Project assignar a la propietat post-build event a

cscript.exe “$(ProjectDir)ModifyMsiToEnableLaunchApplication.js” “$(BuiltOuputPath)”

Doncs ara perquè funcioni correctament és

cscript.exe //E:jscript “$(ProjectDir)ModifyMsiToEnableLaunchApplication.js” “$(BuiltOuputPath)”