Bienvenue à Blogs CodeS-SourceS Identification | Inscription | Aide

[WP7] Dynamically toggle PanoramaItem visibility

A strange issue with the Panorama control, that has been brought to my attention by @lancewmccarthy, and which has also been encountered by some people on StackOverflow.

The original scenario was a bit too complex for a blog post, but we can reproduce it in a much simpler way.

Create a new page, and add a panorama control called ‘Panorama’. Then add two PanoramaItem, and put a button in the first one:

   1: <controls:Panorama x:Name="Panorama">
   2:     <controls:PanoramaItem Header="Item1" x:Name="Item1">
   3:         <Button Content="Test" Click="Button_Click" />
   4:     </controls:PanoramaItem>
   5:     <controls:PanoramaItem Header="Item2" x:Name="Item2" >
   6:     </controls:PanoramaItem>
   7: </controls:Panorama>

In the click event handler of the button, we toggle the visibility of the second item of the panorama:

   1: private void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:     this.Item2.Visibility = this.Item2.Visibility == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
   4: }

Start the application, try tapping on the button, and the visibility of the PanoramaItem changes as expected.

Now, let’s just change the XAML to set the visibility of the second item of the panorama to ‘Collapsed’:

   1: <controls:Panorama x:Name="Panorama">
   2:     <controls:PanoramaItem Header="Item1" x:Name="Item1">
   3:         <Button Content="Test" Click="Button_Click" />
   4:     </controls:PanoramaItem>
   5:     <controls:PanoramaItem Header="Item2" x:Name="Item2" Visibility="Collapsed">
   6:     </controls:PanoramaItem>
   7: </controls:Panorama>

Start the application again, tap on the button, and… Nothing happens! What’s going on?

Diving a bit in the Panorama control source code, using good ol’ friend Reflector, we can see that the Panorama host a PanoramaPanel control. The PanoramaPanel contains most of the items placement logic, and has a ‘VisibleChildren’ property. Looks promising!

image

Only a handful of methods access this property, and we can quickly conclude that the ‘VisibleChildren’ collection is populated only by the `MeasureOverride’ method. From there, we can elaborate a theory: at loading time, our panorama item isn’t visible, and therefore isn’t added to the `VisibleChildren’ collection. Later, when we change the visibility of the PanoramaItem, the panorama’s position isn’t invalidated, so the list of visible items isn’t refreshed, and the PanoramaItem isn’t added back to the ‘VisibleChildren’ collection.

It’s easy to test, let’s just change our click event handler to force the panorama to re-compute its size:

   1: private void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:     this.Item2.Visibility = this.Item2.Visibility == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
   4:     this.Panorama.Measure(Size.Empty);
   5: }
And sure enough, it works! Now, the ‘Measure’ method expects a parameter. Giving ‘Size.Empty’ basically tells the control “Use all the space available”. While it should be ok in most case, it may have unforeseen consequences in some specific scenarios.

Unfortunately, just calling the ‘InvalidateMeasure’ method of the panorama doesn’t work. It looks like the event isn’t propagated to the child panel. And we can’t directly access the child panel because it isn’t exposed in a public property. Is there another way out?

By randomly browsing the source code of the PanoramaPanel with Reflector, we can see a ‘NotifyDefaultItemChanged’ method, which looks quite promising:

   1: internal void NotifyDefaultItemChanged()
   2: {
   3:     base.InvalidateMeasure();
   4:     base.InvalidateArrange();
   5:     base.UpdateLayout();
   6: }

Now if we could just trigger this method, our problem would be solved. Using the ‘Analyze’ feature of Reflector, we can see that this method is called by the setter of the ‘DefaultItem’ property of the panorama:

image

That’s perfect! We just have to change the panorama’s default item to ensure that our PanoramaItem becomes visible as expected. Since we don’t want to disrupt the panorama, and since there’s no specific check in the property setter, we just assign back the value of the property to itself:

   1: private void Button_Click(object sender, RoutedEventArgs e)
   2: {
   3:     this.Item2.Visibility = this.Item2.Visibility == Visibility.Collapsed ? Visibility.Visible : Visibility.Collapsed;
   4:     this.Panorama.DefaultItem = this.Panorama.DefaultItem;
   5: }

Now the panorama is behaving as expected, and the visibility of the PanoramaItem is correctly updated, even if the item was collapsed when the page was loaded.

Publié dimanche 1 juillet 2012 16:35 par KooKiz
Ce post vous a plu ? Ajoutez le dans vos favoris pour ne pas perdre de temps à le retrouver le jour où vous en aurez besoin :

Commentaires

Pas de commentaires
Les commentaires anonymes sont désactivés

Les 10 derniers blogs postés

- Simuler facilement l’envoi de mail par Blog de Jérémy Jeanson le il y a 3 heures et 42 minutes

- ProcDump 6.0 : support du filtrage sur messages d'exceptions .NET, des filtres multiples et du ciblage par nom de service par CoqBlog le 05-20-2013, 14:50

- Votez pour le TOP 10 des influenceurs SharePoint francophones ! par Le blog de Patrick [MVP SharePoint] le 05-20-2013, 12:59

- [Conf’SharePoint] Dernier rappel ! :-) par Le blog de Patrick [MVP SharePoint] le 05-20-2013, 09:09

- [ #SharePoint 2013 ] les modèles de sites standards… par Le blog de Patrick [MVP SharePoint] le 05-20-2013, 09:03

- 10 erreurs de compréhension concernant SharePoint… par Le blog de Patrick [MVP SharePoint] le 05-20-2013, 08:27

- Conf’SharePoint : 10 bonnes raisons pour ne pas la rater par Le petit blog de Pierre / Pierre's little blog le 05-14-2013, 02:24

- [Event] Soirée de lancement Agile .NET France à Lyon par Blog Agile/ALM de Vincent THAVONEKHAM le 05-13-2013, 01:29

- .NET / Debug : inspection de la mémoire d'applications .NET (dump ou processus live) : première livraison d'une librairie .NET par Microsoft par CoqBlog le 05-11-2013, 22:21

- SharePoint : Incompatibilité avec Internet Explorer 10 (IE10) par Blog Technique de Romelard Fabrice le 05-08-2013, 16:29