lunedì 3 gennaio 2011

Preserve and Restore ListBox State for Windows Phone

Per salvare e recuperare lo stato selle pagine su phone 7 c'è un articolo interessante su msdn :

Nell'articolo mancano però i metodi per gestire il controllo ListBox, vi aggiungo qui sotto i metodi da aggiungere per poter agilmente salvare lo stato di questo controllo :


   1:  /// <summary>
   2:  /// Saves the scroll offset of a ListBox to the state dictionary.
   3:  /// </summary>
   4:  /// <param name="state">The calling page's state dictionary.</param>
   5:  /// <param name="scrollViewer">The ListBox to be preserved.</param>
   6:  public static void PreserveState(IDictionary<string, object> state, ListBox listbox)
   7:  {           
   8:              
   9:      ScrollViewer viewer = ((VisualTreeHelper.GetChild(listbox, 0) as FrameworkElement).FindName("ScrollViewer") as ScrollViewer);
  10:      if (viewer != null) {
  11:          state[listbox.Name + "_HorizontalOffset"] = viewer.HorizontalOffset;
  12:          state[listbox.Name + "_VerticalOffset"]   = viewer.VerticalOffset;
  13:      }
  14:   
  15:      state[listbox.Name + "_selectedIndex"] = listbox.SelectedIndex;
  16:  }
  17:   
  18:  public class datListBox {
  19:      public double offsetX=0;
  20:      public double offsetY=0;
  21:      public int selectedIndex=-1;
  22:  }
  23:   
  24:  /// <summary>
  25:  /// Retrieves the saved scroll offset from the state dictionary and creates a delegate to
  26:  /// restore the scroll position on the page's first render.
  27:  /// </summary>
  28:  /// <param name="state">The calling page's state dictionary</param>
  29:  /// <param name="scrollViewer">The ListBox to be restored</param>
  30:  public static datListBox RestoreState(IDictionary<string, object> state, ListBox listbox)
  31:  {
  32:      datListBox data = new datListBox();
  33:      data.offsetX = TryGetValue<double>(state, listbox.Name + "_HorizontalOffset", 0);
  34:      data.offsetY = TryGetValue<double>(state, listbox.Name + "_VerticalOffset", 0);
  35:      data.selectedIndex = TryGetValue<int>(state, listbox.Name + "_selectedIndex", -1);
  36:   
  37:      ScheduleOnNextRender(delegate { RestoreState(listbox,data); });
  38:      return data;
  39:  }
  40:   
  41:  private static void RestoreState(ListBox listbox,datListBox data)
  42:  {
  43:      if (listbox == null || data == null ) return;
  44:      ScrollViewer viewer = ((VisualTreeHelper.GetChild(listbox, 0) as FrameworkElement).FindName("ScrollViewer") as ScrollViewer);
  45:      if (viewer != null)
  46:      {
  47:          viewer.ScrollToHorizontalOffset(data.offsetX);
  48:          viewer.ScrollToVerticalOffset(data.offsetY);
  49:      }
  50:  }

Nel metodo RestoreState() potete aggiungere anche il ripristino dell'elemento selezionato se vi interessa (basta aggiungere : listbox.SelectedIndex = data.selectedIndex;)
Un'altra cosa, ho trovato un piccolo Bug nell'articolo MSDN sopra indicato, nel metodo PreserveState del controllo ScrollViewer viene salvato due volte il VerticalOffset :


   1:  public static void PreserveState(IDictionary<string, object> state, ScrollViewer scrollViewer)
   2:  {
   3:    state[scrollViewer.Name + "_HorizontalOffset"] = scrollViewer.VerticalOffset;
   4:    state[scrollViewer.Name + "_VerticalOffset"] = scrollViewer.VerticalOffset;
   5:  }

Modificatelo così :

   1:  public static void PreserveState(IDictionary<string, object> state, ScrollViewer scrollViewer)
   2:  {
   3:   state[scrollViewer.Name + "_HorizontalOffset"] = scrollViewer.HorizontalOffset;
   4:   state[scrollViewer.Name + "_VerticalOffset"] = scrollViewer.VerticalOffset;
   5:  }