Over a million developers have joined DZone.

Keeping popups above the bottom app bar in Windows 8.1 store apps

·

Recently, I wrote about the KeepFromBottomBehavior that helped me to deal with popups that appeared on the bottom of the screen, but were covered by the app bar when using the full screen by applying ApplicationViewBoundsMode.UseCoreWindow. When I started porting parts of Travalyzer to Windows 8.1 as a companion app, I kind of ran into the same problem: popup appearing ‘under’ the bottom app bar.

image

(This time I replaced the map by a simple blue area, to prevent you from needing to install the Bing Maps SDK to run the sample).

So I kind-of ported my KeepFromBottomBehavior to Windows 8.1, and got the following result.image

Which is exactly what I wanted. If the App bar is open, the popup up appears above the App bar, if it is closed, it appears on the very bottom of the screen:

image

The code is actually a lot simpler than the KeepFromBottomBehavior for Windows Phone8.1,

using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace WpWinNl.Behaviors
{
  public class KeepFromBottomBehavior : SafeBehavior<FrameworkElement>
  {
    private double originalBottomMargin;
    private AppBar bottomAppBar;
    protected override void OnSetup()
    {
      var page = AssociatedObject.GetVisualAncestors().OfType<Page>().First();
      bottomAppBar = page.BottomAppBar;
      bottomAppBar.Opened += BottomAppBarManipulated;
      bottomAppBar.Closed += BottomAppBarManipulated;
      originalBottomMargin = AssociatedObject.Margin.Bottom;
      UpdateBottomMargin();
      base.OnSetup();
    }

    void BottomAppBarManipulated(object sender, object e)
    {
      UpdateBottomMargin();
    }

    protected override void OnCleanup()
    {
      bottomAppBar.Opened -= BottomAppBarManipulated;
      bottomAppBar.Closed -= BottomAppBarManipulated;
      base.OnCleanup();
    }

    private async void UpdateBottomMargin()
    {
      await Task.Delay(1);
      var currentMargins = AssociatedObject.Margin;

      var newMargin = new Thickness(currentMargins.Left, 
        currentMargins.Top, currentMargins.Right,
        originalBottomMargin + (bottomAppBar.IsOpen ?
              bottomAppBar.ActualHeight : 0));
      AssociatedObject.Margin = newMargin;
    }

    public double WindowHeight { get; set; }
  }
}

Here we seen this behavior works very different from it’s Windows Phone counterpart. It finds the Page this behavior is on using the GetVisualAncestors extension methods fromWpWinNl, and attaches itself to the bottom AppBar’s Opened and Close events. When these events are fired, the bottom margin of the whole panel this behavior is attached is increased with the actual height of the bottom AppBar. Easy ask cake. The only weird thing is the Task.Delay(1). I found out that if you omit that, the behavior’s actions will flip-flop, that is, it won’t move the panel when you open the AppBar, but it will move it up when you close it. I think this has something to do with the calculation of the ActualHeight not being done yet. By using Task.Delay, with however small the value, the whole event is asynchronous and thus the calculation is not being blocked by whatever it was being blocked ;)

The WindowHeight is no longer a dependency property and is in fact no longer used, it’s just kept here to keep the behavior’s signature identical to it’s Windows Phone counterpart. In the sample solution you will see this behavior works stand-alone, it does not need SizeListenerBehavior as a companion to bind to.

The sample solution is essentially the same as in the previous article, but contains both code for Windows and Windows Phone now.

Topics:

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}