locked
How do I reuse an AppBar? RRS feed

  • Question

  • I want to use the same app bar across most of my pages, so I figured that the best thing to do was to put it into app.xaml, like this:

    <AppBar x:Key="AppBar" />

    Unfortunately, when you do that, and reference it like this:

    <Page
        x:Class="ReuseAppBar.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        TopAppBar="{StaticResource AppBar}">
        <Page.BottomAppBar>
            <AppBar/>
        </Page.BottomAppBar>
        <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        </Grid>
    </Page>

    then you get a very useful exception: "Value does not fall within the expected range."

    What exactly is the expected range?

    How do I reuse an AppBar?  I don't want to duplicate that amount of code across so many pages.

    ...Stefan

    Monday, June 18, 2012 2:44 AM

Answers

  • Mark,

    Ok, have been doing some more playing around.  On the basis of what you've said I think the best way to handle this is to create a custom app bar derived from AppBar. e.g (using the globalpage in the sample):

    <AppBar
        x:Class="AppBarControl.GlobalAppBar"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400"
        Padding="10,0,10,0">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50*"/>
                <ColumnDefinition Width="50*"/>
            </Grid.ColumnDefinitions>
            <StackPanel x:Name="LeftCommands" Orientation="Horizontal" Grid.Column="0" HorizontalAlignment="Left">
                <Button x:Name="Back" AutomationProperties.Name="Back" Style="{StaticResource BackAppBarButtonStyle}" HorizontalAlignment="Left"/>
            </StackPanel>
            <StackPanel x:Name="RightCommands" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right">
            </StackPanel>
        </Grid>
    </AppBar>

    Unfortunately, because we can't apply a style to the page's TopAppBar property and as you say a UIElement can't be used in this situation, so I can't do something obvious like this:

    <Style TargetType="Page"> <Setter Property="TopAppBar"> <Setter.Value> <AppBarControl:GlobalAppBar/> </Setter.Value> </Setter> </Style>

    So you end up having to apply the AppBar manually in each page, e.g:

    <Page.TopAppBar>
        <local:GlobalAppBar/>
    </Page.TopAppBar>    

    Is quite disappointing that a reuse scenario hasn't really ben thought through here. I have unnecessary code in every page, where I should be able to do it through the styling system. It is one of the truly great things about Xaml is the ability to maximise reuse through styles, but unfortunately there is no way to do that here.  Hopefully this can be improved for future releases.

    ...Stefan

    • Marked as answer by StefanOlson Monday, June 25, 2012 12:24 AM
    Monday, June 18, 2012 10:58 PM

All replies

  • I tried to add an AppBar as a global resource in App.xaml, and Visual Studio tells me that it's not posible. So an alternate solution may be doing it programmatically.

    In App.xaml.cs you may create a global appbar:

            public static AppBar GlobalAppBar = new AppBar();

    Initialize it with buttons, etc., and then use it in every page with:

    this.BottomAppBar = App.GlobalAppBar;


    --------------------------------------------------------------------------------

    Alejandro Campos Magencio - Microsoft Escalation Engineer - Forum Moderator
     If my reply answers your question, please mark this post as answered.

    Monday, June 18, 2012 10:06 AM
    Moderator
  • That's not a good way to code - other people coming to examine my code in the future are not going to expect that.  Why is not possible to create an appbar in app.xaml?  To me that's a bug - it's possible on Windows phone.  Why is there no consistency?

    Creating it in app.xaml can create a gorgeous clean way of working.

    ...Stefan

    Monday, June 18, 2012 6:56 PM
  • 
    
    I think it is better to create a userControl and drop it in the AppBar

    http://leeontech.wordpress.com/

    Monday, June 18, 2012 8:31 PM
  • @Lee,

    That seems the only alternative option.  Personally, I prefer to reuse the AppBar, it makes for much simpler Xaml, using a user control is inconsistent with the way that you can do things on the phone.  I cannot see any reason why you could not reuse an AppBar.

    ...Stefan

    Monday, June 18, 2012 8:33 PM
  • Check out the AppBar SDK sample which shows a way of doing this. Basically you have the AppBar outside in the Frame element and just change out the pages under it.

    http://code.msdn.microsoft.com/windowsapps/XAML-AppBar-control-sample-2aa1cbb4

    -mark
    Program Manager
    Microsoft
    This post is provided "as-is"
    Monday, June 18, 2012 9:08 PM
  • Mark,

    Thanks, that's a partial solution to the problem. However I have other AppBars that I need to reuse, different bars on different pages, but the same bar on multiple pages.  I am still unclear as to why I can't reuse an AppBar?

    ...Stefan

    Monday, June 18, 2012 9:31 PM
  • UI elements cannot be used as a resource in App.Xaml. You could write code to remove app bar from one page to another page, but an Uielement cannot be a child to multiple parents.

    -mark
    Program Manager
    Microsoft
    This post is provided "as-is"
    Monday, June 18, 2012 9:38 PM
  • Mark,

    Ok, have been doing some more playing around.  On the basis of what you've said I think the best way to handle this is to create a custom app bar derived from AppBar. e.g (using the globalpage in the sample):

    <AppBar
        x:Class="AppBarControl.GlobalAppBar"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        d:DesignHeight="300"
        d:DesignWidth="400"
        Padding="10,0,10,0">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50*"/>
                <ColumnDefinition Width="50*"/>
            </Grid.ColumnDefinitions>
            <StackPanel x:Name="LeftCommands" Orientation="Horizontal" Grid.Column="0" HorizontalAlignment="Left">
                <Button x:Name="Back" AutomationProperties.Name="Back" Style="{StaticResource BackAppBarButtonStyle}" HorizontalAlignment="Left"/>
            </StackPanel>
            <StackPanel x:Name="RightCommands" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right">
            </StackPanel>
        </Grid>
    </AppBar>

    Unfortunately, because we can't apply a style to the page's TopAppBar property and as you say a UIElement can't be used in this situation, so I can't do something obvious like this:

    <Style TargetType="Page"> <Setter Property="TopAppBar"> <Setter.Value> <AppBarControl:GlobalAppBar/> </Setter.Value> </Setter> </Style>

    So you end up having to apply the AppBar manually in each page, e.g:

    <Page.TopAppBar>
        <local:GlobalAppBar/>
    </Page.TopAppBar>    

    Is quite disappointing that a reuse scenario hasn't really ben thought through here. I have unnecessary code in every page, where I should be able to do it through the styling system. It is one of the truly great things about Xaml is the ability to maximise reuse through styles, but unfortunately there is no way to do that here.  Hopefully this can be improved for future releases.

    ...Stefan

    • Marked as answer by StefanOlson Monday, June 25, 2012 12:24 AM
    Monday, June 18, 2012 10:58 PM
  • i try to do like that adding a new user control to the solution and renaming User control tag as App bar and did it like your code 

    but it getting a error from AppBar tag in XML file "value does not fall within expected range" 

     public sealed partial class CustomTopAppBar : AppBar
        {
            public CustomTopAppBar()
            {
                this.InitializeComponent();
            }
        }

    you know how to solve this 

    thanx in advance!


    JanithA

    Friday, September 7, 2012 12:50 PM
  • The Microsoft example of using a frame for the pages, is not very elegant, IMHO.  It's too bad that we can't just declare an AppBar in the app.xaml resource dictionary--but as someone pointed out, it inherits from UIElement and those objects can't exist in multiple places at the same time.  It seems like the best hack is:

    1) Add a new user control to your project, example myappbar
    2) Replace "UserControl" with "AppBar" in the .xaml, and in the .cs files.
    3) In OnNavigatedTo, do a BottomAppBar = new myappbar();

    Sunday, November 4, 2012 8:49 PM