Mostrando entradas con la etiqueta WinRT. Mostrar todas las entradas
Mostrando entradas con la etiqueta WinRT. Mostrar todas las entradas
domingo, 25 de noviembre de 2012
StratexStudio está en La Tienda
Hace un par de días conseguimos por fin certificar y publicar StratexStudio.
Nuestros usuarios de StratexLive podrán conectarse al sitio de sus compañías con la su URL y su usuario de StratexLive y empezar a usar sus Surfaces para enseñarles a sus compañeros lo bien que van sus empresas y lo bonita que es su nuevo aparato con Windows 8.
La nueva aplicación tiene informes para medir el rendimiento, los riesgos y los controles así como la actividad en el portal y una visión anidada de la jerarquía de la organización.
Échale un ojo a la página de la Tienda de Windows de StratexStudio para ver las fotos y, si tienes un dispositivo Windows 8, bájatela y la pruebas, que es gratis..
jueves, 15 de noviembre de 2012
Click funciona pero Tapped causa error en Windows 8
Nos han rechazado la app de la tienda de Windows 8 porque peta cuando el usuario toca o hace Tap o pone su zarpa en una grid view. Como no tenemos una surface estábamos haciendo las pruebas en el simulador, pero con la herramienta del ratón y no con la del dedo y funcionaba perfectamente…
Se cuelga cada vez que tocas en un elemento dentro de una GridView y es curioso porque se cuelga justo en el momento en el que tocas, el código ni siguiera llega a ejecutar el callback. La información del cuelgue tampoco nos da información útil, como era de esperar.
Parece que hay un error en la GridView y tras ser asignada a un DataContext con datos necesita ser refrescada antes de aceptar Taps, aunque funciona bien con los Clicks.
No hay formao yo no la he encontrado de refrescar el UI en WinRT, lo que creo que resolvería el problema, así que he tomado dos caminos diferentes para tratar de evitar el fallo
Los chavales del Windows Store App Lab han dicho que van a buscar una solución al problema pero yo creo que este es uno de esos errores que se arregla con un paquete en el Windows Update… Os mantendré informados si se inventan algo nuevo.
***ACTUALIZACIÓN***
Un experto de Microsoft me ha apuntado que si creas y añades los datos a la GridView en el código y después la añades a la página funciona correctamente. Lo he probado y es verdad.
Los templates en mis GridViews son complejos así que haré UserControls con las GridViews de manera que pueda crearlas con datos en código sin perder la posibilidad de seguir usando MVVM.Esto todavía no lo he probado.
Se cuelga cada vez que tocas en un elemento dentro de una GridView y es curioso porque se cuelga justo en el momento en el que tocas, el código ni siguiera llega a ejecutar el callback. La información del cuelgue tampoco nos da información útil
Parece que hay un error en la GridView y tras ser asignada a un DataContext con datos necesita ser refrescada antes de aceptar Taps, aunque funciona bien con los Clicks.
No hay forma
- Informes de carga rápida: Estoy pre-cargando los contenidos de los informes que cargan rápido cuando se ejecuta la app. Haciendo esto relleno todas las GridViews en páginas diferentes de las que el usuario está viendo, en segundo plano. Una vez que se selecciona la página en donde reside la GridView ésta es renderizada junto con el resto de la página y se solventa el problema.
- Informes de carga lenta: También pre-cargo el contenido de estos informes, pero si el usuario los muestra antes de que se rellene la GridView con lo que los datos se mostrarían pero el control no se refrescaría y el Tapped seguiría fallando. Para evitar esto he cambiado también el comportamiento de la carga de datos. Asigno el DataContext antes y lo actualizo varias veces, una vez por cada paquete de información que recibo. Así el GridView se refresca unas cuantas veces y se soluciona el problema con el Tapped.
Los chavales del Windows Store App Lab han dicho que van a buscar una solución al problema pero yo creo que este es uno de esos errores que se arregla con un paquete en el Windows Update… Os mantendré informados si se inventan algo nuevo.
***ACTUALIZACIÓN***
Un experto de Microsoft me ha apuntado que si creas y añades los datos a la GridView en el código y después la añades a la página funciona correctamente. Lo he probado y es verdad.
Los templates en mis GridViews son complejos así que haré UserControls con las GridViews de manera que pueda crearlas con datos en código sin perder la posibilidad de seguir usando MVVM.
jueves, 6 de septiembre de 2012
Autenticando un Web Service ASMX en SharePoint desde una aplicación WinRT
¿Dónde está el CookieContainer?
Sí amigo, yo también me he preguntado eso.
Estamos creando una aplicación para Windows 8 y necesitamos que se conecte a nuestros servicios web. Conectarse de manera anónima es fácil pero, cuando se trata de conectarse autenticando el usuario, la cosa cambia.
Yo estaba muy seguro, seguro del verbo ignorante y cándido, de que podría usar el mismo método que usaba para crear aplicaciones de WP7. Lo he hecho mil veces y WP7 es más o menos lo mismo que WinRT así que ¿Quién habría pensado que no funcionaría?
Bien, WinRT no es lo mismo que WP7.
Después de crear un SPAuthBridge intenté añadir la cookie de autenticación a mi SoapClient como siempre pero, como probablemente sabes si estás leyendo este post, esta línea no funciona:
En WinRT el objeto SoapClient no tiene CookieContainer asi que tenemos que buscarnos otra manera de añadir la cookie en las llamadas.
El SPAuthBridge va bien. Solo he añadido un método nuevo para obtener la cookie de autenticación del CookieContainer.
Después de eso, solo tienes que seguir los pasos del otro post para autenticarte y después de haberte autenticado correctamente en SharePoint tienes que cambiar la manera en la que añades la cookie a tu SoapClient.
Yo he encontrado dos formas:
La rápida
Cada vez que necesites llamar al servicio web necesitaras añadir la cookie al header y entonces llamar al servicio dentro del mismo OperationContextScope. Más o menos así:
Esto es fácil pero no muy legible y si tienes que llamar al web service unas cuantas veces, seguramente, te vas a aburrir de hacerlo así.
La elegante
En lugar de añadir la cookie cada vez podemos crearnos un Behaviour que se encargue de hacerlo automáticamente.
Para hacerlo necesitas crearte una clase CookieBehavior. Yo he copiado el 99% de la mía de aquí y es así:
Cuando tenemos esta clase ya solo tememos que añadir el Behavior al servicio web en la inicialización y la cookie se añadirá solita cada vez.
Después de haber inicializado el servicio web de esta manera puedes llamar a los métodos sin preocuparte de la autenticación nunca más:
El MaxReceivedMessageSize quizás podría seruna mijita excesivo. Configúralo para que se adapte a tus necesidades pero, ten en cuenta que si lo pones demasiado bajo te va a dar una CommunicationException diciendo que:
Diviértete con la tabletsi es que la tienes, yo estoy todavía esperando la mía.
Sí amigo, yo también me he preguntado eso.
Estamos creando una aplicación para Windows 8 y necesitamos que se conecte a nuestros servicios web. Conectarse de manera anónima es fácil pero, cuando se trata de conectarse autenticando el usuario, la cosa cambia.
Yo estaba muy seguro
Bien, WinRT no es lo mismo que WP7.
Después de crear un SPAuthBridge intenté añadir la cookie de autenticación a mi SoapClient como siempre pero, como probablemente sabes si estás leyendo este post, esta línea no funciona:
MySoapClient.CookieContainer = SharePointAuth.cookieJar;
En WinRT el objeto SoapClient no tiene CookieContainer asi que tenemos que buscarnos otra manera de añadir la cookie en las llamadas.
El SPAuthBridge va bien. Solo he añadido un método nuevo para obtener la cookie de autenticación del CookieContainer.
public string GetAuthenticationCookie() { return string.Format("{0}={1}", "FedAuth", cookieJar.GetCookies(new System.Uri("https://www.mySite.com"))["FedAuth"].Value); }
Después de eso, solo tienes que seguir los pasos del otro post para autenticarte y después de haberte autenticado correctamente en SharePoint tienes que cambiar la manera en la que añades la cookie a tu SoapClient.
Yo he encontrado dos formas:
La rápida
Cada vez que necesites llamar al servicio web necesitaras añadir la cookie al header y entonces llamar al servicio dentro del mismo OperationContextScope. Más o menos así:
using (new OperationContextScope(MyWS.InnerChannel)) { HttpRequestMessageProperty httpRequestProperty = new HttpRequestMessageProperty(); httpRequestProperty.Headers[System.Net.HttpRequestHeader.Cookie] = SharePointAuth.GetAuthenticationCookie(); OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpRequestProperty; UserInfo = await MyWS.GetInfoForUserAsync(); }
Esto es fácil pero no muy legible y si tienes que llamar al web service unas cuantas veces, seguramente, te vas a aburrir de hacerlo así.
La elegante
En lugar de añadir la cookie cada vez podemos crearnos un Behaviour que se encargue de hacerlo automáticamente.
Para hacerlo necesitas crearte una clase CookieBehavior. Yo he copiado el 99% de la mía de aquí y es así:
class CookieBehaviour: IEndpointBehavior { private string cookie; public CookieBehaviour(string cookie) { this.cookie = cookie; } public void AddBindingParameters(ServiceEndpoint serviceEndpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint serviceEndpoint, ClientRuntime behavior) { behavior.ClientMessageInspectors.Add(new CookieMessageInspector(cookie)); } public void ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint serviceEndpoint) { } } public class CookieMessageInspector : IClientMessageInspector { private string cookie; public CookieMessageInspector(string cookie) { this.cookie = cookie; } public void AfterReceiveReply(ref Message reply, object correlationState) { } public object BeforeSendRequest(ref Message request, IClientChannel channel) { HttpRequestMessageProperty httpRequestMessage; object httpRequestMessageObject; if (request.Properties.TryGetValue(HttpRequestMessageProperty.Name , out httpRequestMessageObject)) { httpRequestMessage = httpRequestMessageObject as HttpRequestMessageProperty; } else httpRequestMessage = new HttpRequestMessageProperty(); httpRequestMessage.Headers[System.Net.HttpRequestHeader.Cookie] = cookie; request.Properties.Add(HttpRequestMessageProperty.Name, httpRequestMessage); return null; } }
Cuando tenemos esta clase ya solo tememos que añadir el Behavior al servicio web en la inicialización y la cookie se añadirá solita cada vez.
public MyWSSoapClient InitializeMyWS() { BasicHttpBinding Bind = new BasicHttpBinding(); //////////////////////Transport/////////////////////// Bind.Security.Mode = BasicHttpSecurityMode.Transport; ////////////////////////////////////////////////////// /////////////////////MessageSize////////////////////// Bind.MaxReceivedMessageSize = Int32.MaxValue; ////////////////////////////////////////////////////// EndpointAddress oAddress = new EndpointAddress(SiteUrl + "/_vti_bin/MyWS.asmx"); MyWSSoapClient MyWS = new MyWSSoapClient(Bind, oAddress); CookieBehaviour AuthCookieBehaviour = new CookieBehaviour(SharePointAuth.GetAuthenticationCookie()); MyWS.Endpoint.EndpointBehaviors.Add(AuthCookieBehaviour); return MyWS; }
Después de haber inicializado el servicio web de esta manera puedes llamar a los métodos sin preocuparte de la autenticación nunca más:
private async Task<ObservableCollection<Info>> GetInfo() { GetInfoForUserResponse Information = await MyWS.GetInfoForUserAsync(); return Information.Body.GetInfoForUserResult; }En el método inicializador el poner el SecurityMode del BasicHttpBinding a Transport es necesario porque la aplicación web en la que se aloja el servicio web es HTTPS. Por defecto el SecurityMode está puesto a None y me estaba dando una ArgumentException como esta:
The provided URI scheme 'https' is invalid; expected 'http'.
El MaxReceivedMessageSize quizás podría ser
The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element.
Diviértete con la tablet
miércoles, 5 de septiembre de 2012
Snippet para DependencyProperty con método Call-Back y valor por defecto
Para mi esta es la manera en la que Microsoft debería haber hecho el snippet de DependencyProperty desde el principio.
Uso este un montón y tiene definidos lugares para el valor por defecto, el método call-back e incluso asigna la instancia de la clase que llama al call-back a una variable automaticamente.
Por cierto, podéis encontrar más información sobre cómo crear e importar snippets aquí.
Uso este un montón y tiene definidos lugares para el valor por defecto, el método call-back e incluso asigna la instancia de la clase que llama al call-back a una variable automaticamente.
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"> <CodeSnippet Format="1.0.0"> <Header> <Title>Dependency Property With CallBack</Title> <Shortcut>propdpCallBack</Shortcut> <Description>Creates a dependency property with it's callback method</Description> <Author>Jose Sanchez</Author> <SnippetTypes> <SnippetType>Expansion</SnippetType> <SnippetType>SurroundsWith</SnippetType> </SnippetTypes> </Header> <Snippet> <Declarations> <Literal> <ID>PublicName</ID> <Default>PropertyName</Default> <ToolTip>Public name of the depencency property</ToolTip> </Literal> <Literal> <ID>type</ID> <Default>string</Default> <ToolTip>Type of the property</ToolTip> </Literal> <Literal> <ID>ParentClassType</ID> <Default>UserControl</Default> <ToolTip>Type of the parent class of the dependency property</ToolTip> </Literal> <Literal> <ID>DefaultValue</ID> <Default>string.Empty</Default> <ToolTip>Default value of the dependency property</ToolTip> </Literal> <Literal> <ID>CallBackName</ID> <Default>PropertyCallBackName</Default> <ToolTip>Name of the callback method that will be triggered when the depencency property has changed</ToolTip> </Literal> </Declarations> <Code Language="csharp"><![CDATA[public $type$ $PublicName$ { get { return ($type$)GetValue($PublicName$Property); } set { SetValue($PublicName$Property, value); } } // Using a DependencyProperty as the backing store for $PublicName$. This enables animation, styling, binding, etc... public static readonly DependencyProperty $PublicName$Property = DependencyProperty.Register("$PublicName$", typeof($type$), typeof($ParentClassType$), new PropertyMetadata($DefaultValue$, new PropertyChangedCallback($CallBackName$))); private static void $CallBackName$(DependencyObject obj, DependencyPropertyChangedEventArgs e) { $ParentClassType$ Changed$ParentClassType$ = (obj as $ParentClassType$); //TODO: Implement some actions in Changed$ParentClassType$ }]]> </Code> </Snippet> </CodeSnippet> </CodeSnippets>Espero que os sea tan útil como a mi.
Por cierto, podéis encontrar más información sobre cómo crear e importar snippets aquí.
Suscribirse a:
Entradas (Atom)
No hay comentarios:
Publicar un comentario