Freigeben über


Redefining the App Bar

One of the coolest things about developing Windows Store Apps is the number of powerful features you can add to your App with just a small amount of programming overhead. One of these features is the app bar, an introduction to which can be found here: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh781232.aspx. Usually, the app bar contains UI functionality that doesn’t need to be displayed the entire time (for example, think about a button that provides a hint in a game or allows you to edit the contents of a TextBox).

But don’t let your plans for the app bar end at a few buttons, there’s so much potential to use it in other ways! In this post, I’m going to go through some code for a Windows Store App that makes unconventional use of the app bar.

The Set-Up

I’ve been hearing the phrase “Content is King” quite a bit lately, and it’s true in many applications. The most important content should be the most prominent in the App. Imagine that a travel/adventure agency has an App they use to show customers trip package options. The customer should be able to access a trip’s description and price, but a picture will have much more impact, so it should be as large and unobstructed as possible.

The App is based off of the standard GridView App template, and the ItemViewPage consists of a full-screen picture. I could display the picture, description and price all at once, but I don’t want to lessen the effect of the image by making it smaller or having text permanently laid over it. Placing the project information in the app bar would allow the user to access and dismiss it easily and naturally, preserving the picture’s size and clarity.

 Displaying Information

I want to display a description and price in the App Bar, so all I have to do is add an app bar to my page, and place the content inside it.

  1.     <Page.BottomAppBar>
  2.         <AppBar x:Name="bottomAppBar" Height="200" Opened="AppBarOpened" BorderBrush="Transparent" Background="#DD333333">
  3.             <Grid>
  4.                 <Grid.ColumnDefinitions>
  5.                     <ColumnDefinition Width="*"/>
  6.                     <ColumnDefinition Width="*"/>
  7.                 </Grid.ColumnDefinitions>
  8.  
  9.                 <StackPanel x:Name="infoStack" Grid.Column="0" Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="20,0,0,0">
  10.                     <TextBlock x:Name="infoHeader" FontSize="30" HorizontalAlignment="Left" Text="Description"/>
  11.                     <TextBlock x:Name="infoText" Style="{StaticResource infoTextStyle}" TextWrapping="Wrap"/>
  12.                 </StackPanel>
  13.  
  14.                 <StackPanel x:Name="priceInfo" Grid.Column="1" Orientation="Vertical" VerticalAlignment="Center" HorizontalAlignment="Center">
  15.                     <TextBlock x:Name="priceHeader" FontSize="30" Text="Cost"/>
  16.                     <TextBlock x:Name="price" Style="{StaticResource infoTextStyle}" Grid.Column="3"/>
  17.                 </StackPanel>
  18.             </Grid>
  19.         </AppBar>
  20.     </Page.BottomAppBar>

screenshot

However, as I flip from item to item inside the FlipView, I want the information inside my app bar to update accordingly. The next step, then, is combining the app bar with a data-bound control.

 Data-Bound Controls

I’ve bound the FlipView in the item detail page to the Items in the selected group, and I’ve created an ItemTemplate that contains an Image XAML control bound to the Image property of the currently selected item. As I flip through each item in the FlipView, the image will update. Unfortunately, I can’t bind the description and price inside the app bar in the same way, so that information won’t change as I flip from picture to picture.

I can easily work around this blockage by manually updating the information every time the user flips to a new item. Luckily, FlipView has the SelectionChanged event, which fires each time the item is changed. First, I need to register the ChangeInfoPanel method as the handler for the SelectionChanged event:

  1.         <FlipView
  2.             x:Name="flipView"
  3.             AutomationProperties.AutomationId="ItemsFlipView"
  4.             AutomationProperties.Name="Item Details"
  5.             Grid.RowSpan="2"
  6.             ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
  7.             SelectionChanged="ChangeInfoPanel">
  8.  
  9.             ...
  10.  
  11.         </FlipView>

Then I need to implement ChangeInfoPanel to update the contents of the app bar using information from the SelectedItem property of the FlipView:

  1.         private void ChangeInfoPanel(object sender, SelectionChangedEventArgs e)
  2.         {
  3.             SetInfoPanel();
  4.         }
  5.  
  6.         private void SetInfoPanel()
  7.         {
  8.             var item = this.flipView.SelectedItem as SampleDataItem;
  9.  
  10.             pageTitle.Text = item.Group.Title;
  11.             infoHeader.Text = item.Title;
  12.             infoText.Text = item.Description;
  13.             price.Text = item.Price;
  14.         }

Now every time I change the item in the FlipView, the information displayed in the app bar will update to match. However, there’s one more step I need to take to address the edge case of when the app bar is opened if the user hasn’t yet changed the selection. To solve this problem, I’ll update the contents every time the app bar is opened by registering a handler for the AppBarOpened event:

  1.      <Page.BottomAppBar>
  2.         <AppBar x:Name="bottomAppBar" Height="200" Opened="AppBarOpened">
  3.             
  4.             ...
  5.         
  6.         </AppBar>>
  7.      </Page.BottomAppBar>

 

  1.         private void AppBarOpened(object sender, object e)
  2.         {
  3.             SetInfoPanel();
  4.         }

The app bar will now always display the correct information no matter what the user is looking at or at what point they decide to open it. However, I still need to make a few aesthetic changes to make my app bar a quality feature.

Appearance

An app bar can be closed by making the same motion used to open it, or by touching any part of the screen it doesn’t occupy. This means that in my App, the app bar closes whenever the user flips to a new item. I only want it to close when the user makes the appropriate gesture. To fix this, all I have to do is set the app bar’s IsSticky property to true.

Finally, I want to change the color and opacity of the app bar so that while its text is clearly visible over any image, it doesn’t completely obscure the picture behind it. White text shows up well over a dark gray background, so I’ll use the color with the hex code “#333333”. I can then set the opacity of the background by adding a prefix to this code. The opacity is represented by a two-digit hex number in the range “00” to “FF” (clear and opaque respectively). For example, a clear background would have the code “#00333333”, while “#FF333333” would make it solid. I want my app bar to be dark, but not completely opaque, so I need to set the background to be “#DD333333”.

After these two changes, the code looks like this:

  1.      <Page.BottomAppBar>
  2.         <AppBar x:Name="bottomAppBar" Height="200" Opened="AppBarOpened" Background="DD333333">
  3.             
  4.             ...
  5.         
  6.         </AppBar>>
  7.     </Page.BottomAppBar>

screenshot2

Now my app bar looks and behaves exactly how I want it to. It updates itself to always provide the correct information, and is visually compelling. With a few relatively simple modifications, I’ve redefined what the app bar can be to something that suits my needs perfectly!