Threading Considerations for Binding and Change Notification in XAML

I read a very similar article about how to work with MVVM and multithreading aspects. The problem is well known; in XAML’s Binding features, if you want to communicate any change to UI through Binding object, you need to implement INotifyPropertyChanged on model class, this interface has an event named PropertyChanged that is needed to update the UI, however in multithreading scenarios, you could have secondary threads modifying the model and this implies that the PropertyChanged event will be caught on a secondary thread and then you will the following exception:

Threads other than the UI thread are not allowed to access or manipulate UI objects

In this article you can read how to solve the problem in Silverlight (for WPF and WP as well) but it is not suitable for Portable Library scenarios. In Portable Library we have neither the Deployment class or even the Dispatcher class, so we have to take the SynchronizationContext class.

Implementation is really easy, you need to declare a global class field as follows

private SynchronizationContext _context = SynchronizationContext.Current;

Now, you have in _context the thread which created the class, you need to ensure that this is the same as controls’ thread: Thread UI

The next step is :


protected virtual void OnPropertyChanged(string propertyName)

{

PropertyChangedEventHandler handler = this.PropertyChanged;

if (handler != null)

{

var e = new PropertyChangedEventArgs(propertyName);

if (SynchronizationContext.Current == _context)

{

handler(this, e);

}

else

{

_context.Post(obj =>

{

handler(this, e);

}, null);

}

}

}

_context.Post is called only if the current thread is not the same as the creator thread.

Anuncis

System.Runtime error en WP8 y librerías portables

Un caso raro es cuando usamos librerías portables y Microsoft.Bcl no da un error de compilación System.Runtime. En un primer momento no tenemos muy claro de que se trata y tampoco nos da ninguna pista de que puede ser.

Después de buscar y buscar resulta ser un bug de NuGet en que te pone una redirección en el archivo app.config

 

<dependentAssembly>

<assemblyIdentity name=”System.Runtime” publicKeyToken=”b03f5f7f11d50a3a” culture=”neutral” />

        <bindingRedirect oldVersion=”0.0.0.0-2.6.3.0″ newVersion=”2.6.3.0″ />

</dependentAssembly>

 

De modo que debes eliminar esa línea para que todo funcione correctamente otra vez.

<dependentAssembly>

<assemblyIdentity name=”System.Runtime” publicKeyToken=”b03f5f7f11d50a3a” culture=”neutral” />

</dependentAssembly>

Llibreries portables i Thread UI

Amb .NET 4 apareixen les llibreries portables que penso que són fantàstiques per poder fer una programació completament reutilitzable en les diferents tecnologies que tenim disponibles amb Microsoft .NET : Windows Apps, Windows 8 Store, Windows Phone i Silverlight.

Hem de saber però que aquest tipus de llibreries utilitzen un subconjunt de les característiques que poden tenir en comú les diferents tecnologies i abans de posar-nos a fer res hem de consultar quines funcionalitats ens permeten fer les llibreries portables.

Hi ha un aspecte que sempre ens trobem que és com fem referència al Thread UI de l’aplicació. El Dispatcher no el podem fer servir des de les llibreries portables. Tenim la clase SynchronizationContext per fer-ho.

De fet, l’ús és molt senzill, declarem una variable a nivell de classe com aquesta

#región Fields

private SynchronizationContext _context = SynchronizationContext.Current;

#endregion

 

I llavors sempre que vulguem assegurar-nos que una funció s’executi al mateix thread que ha creat la classe llavors:

if (SynchronizationContext.Current == _context)

{

/*Do something */

}

else

{

/*El thread actual no és el mateix */

_context.Post(obj =>

{

/*Do something */

},null);

}

Fixa’t que el que mira és si el thread actual és el mateix que ha creat la classe, per tant l’únic que ens hem de preocupar és que el Thread UI creí la classe.
Més informació:

Portable Class Library and ObservableCollection, updating UI Thread

Portable class library equivalent of Dispatcher.Invoke or Dispatcher.RunAsync

 

 

 

Navegación a paginas XAML de otros ensamblados

Tanto en WPF como en Silverlight como en Windows Phone trabajamos con ventanas escritas en XAML que son XML que definen la interface de usuario.

Puede ser muy habitual tener definidas estas ventanas en otros ensamblados, como por ejemplo librerías, y en el momento de querer navegar hasta esta ventana tenemos la duda de como se puede hacer ya que el servicio de navegación en WPF funciona con Uri.

Así que, cual es la Uri de una ventana definida en otro ensamblado?

/{assemblyName};component/{pathToResource}

Como por ejemplo : “/SharedPages;component/TestPage.xaml” donde SharedPages es el nombre del ensamblado y /TestPage.xaml la ruta a partir de la raíz del proyecto para encontrar la ventana.

Animar Visibility en Silverlight

Las animaciones es una de las características que encuentro más interesantes en WPF.

Si alguna vez se te plantea la animación de propiedades de un control de ventana tienes que usar el ObjectAnimationUsingKeyFrames.

Si tu caso es animar la propiedad Visibility aqui tienes un ejemplo que he encontrado en el link que tienes en más información pero mira bien porque no es la respuesta marcada como correcta.

<Storyboard x:Name="VisStory">
    <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="LayoutRoot" Storyboard.TargetProperty="(UIElement.Visibility)">
     <DiscreteObjectKeyFrame KeyTime="00:00:00">
      <DiscreteObjectKeyFrame.Value>
       <Visibility>Collapsed</Visibility>
      </DiscreteObjectKeyFrame.Value>
     </DiscreteObjectKeyFrame>
     <DiscreteObjectKeyFrame KeyTime="00:00:01">
      <DiscreteObjectKeyFrame.Value>
       <Visibility>Visible</Visibility>
      </DiscreteObjectKeyFrame.Value>
     </DiscreteObjectKeyFrame>
    </ObjectAnimationUsingKeyFrames>
</Storyboard>

 

Más información

Visibility animation

 

Bing Maps Draggable Pushpin

Bing maps està completament integrat a les tecnologíes de .Net com ASP.NET, WPF, Silverlight i Windows Phone. L’ús de la API és molt senzill.

Per començar a treballar amb ella primer necessites descarregar-te l’SDK de Bing Maps i aconseguir la teva clau de desenvolupador gratuitament.

Tota la informació i els passos a seguir els trobeu aqui: Bing Maps for Developers

En el cas que m’ocupa aquesta entrada vull parlar del control Pushpin de l’espai de noms Microsoft.Phone.Controls.Maps en Windows Phone.

Des de la pàgina de Microsoft pots trobar la informació de com es treballa amb els Pushpins i creume que no és gens complicat. Aqui tens una part de codi amb XAML que et permet incloure una llista de Pushpins enllaçada a una font de dades.

<my:Map  Name="map1" ZoomBarVisibility="Visible" ZoomLevel="16" Center="{Binding Location}">
    <my:MapLayer Visibility="{Binding VisibilityLayer}">
       <my:MapItemsControl ItemsSource="{Binding LlistaPushpins}">
           <my:MapItemsControl.ItemTemplate>
              <DataTemplate>
                <my:Pushpin Content="{Binding Contingut}" Location="{Binding Location}" >
                </my:Pushpin>
              </DataTemplate>
           </my:MapItemsControl.ItemTemplate>
       </my:MapItemsControl>
    </my:MapLayer>
</my:Map>

El que no et fa la SDK estàndard del Bing és poder arrosegar un Pushpin de un punt a un altre del mapa. Per sort la comunitat ja ha resolt aquest problema i penso jo d’una manera molt nítida si ens fixem en la resolució proposada al següent enllaç:

Draggable PushPins

Simplement es tracta de crear una clase que hereda de Behavior<Pushpin> que s’adjunta a l’event MouseLeftButtonDown per accedir a la propietat Location del Pushpin i assignar-l’hi la posició del mouse respecte l’area que ocupa el mapa.

El codi en XAML que has d’utilitzar després és simplement:

<my:Map  Name="map1" ZoomBarVisibility="Visible" ZoomLevel="16" Center="{Binding Location}">
<my:MapLayer >
     <my:Pushpin Location="{Binding Location,Mode=TwoWay}" Style="{StaticResource PushpinStyle2}" >
          <interactivity:Interaction.Behaviors>
               <behavior:DraggablePushpin />
          </interactivity:Interaction.Behaviors>
     </my:Pushpin>
</my:MapLayer>
</my:Map>

El resultat és el següent si seguim el que indica el post que faig referència:

1) Punt inicial del Pushpin

2) Desplaçar per el mapa (Drag)

3) Avís de canvi de ubicació

4) Pushpin canviat

Més informació:

Draggable PushPins

Draggable Pushpins using Bing Maps Silverlight Control

Combobox Silverlight Error 4004

Amb Silverlight 4 el control ComboBox dóna un error particular – no ho he provat amb els altres -. Aquest error no es pot debugar i té el codi 4004 amb l’excepció XamlInvalid. Després de hores i hores trencant-me el cap la conclusió és la següent:

Quan des de codi omplim la propietat ItemsSource del control, si després actualitzem la llista, apareix aquest error.

myComboBox.ItemsSource = <<operació que retorna la llista>>;
(myComboBox.ItemsSource as List<Element>).Add(new Element {nom="nou valor", codi=1});

Aquesta operació pot semblar molt normal però provoca aquest error. El que s’ha de fer és treballar amb la llista abans d’assignar-la a ItemsSource

List<Element> llista = <<operació que retorna la llista>>;
llista.Add(new Element {nom="nou valor", codi=1});
myComboBox.ItemsSource = llista;