Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

Part 5: Basics of Layout and Events

Download

Right click “Save as…”

Source Code: http://aka.ms/absbeginnerdevwp8
PDF Version: http://aka.ms/absbeginnerdevwp8pdf

In this lesson I want to talk about layout, or in other words, how controls are positioned and arranged on your app's user interface.

So, my game plan:

  1. We'll start by talking about the two primary elements used in layout and positioning: the Grid element and StackPanel element.
  2. With regards to the Grid, I'll talk about defining rows and columns and various sizing options and techniques you can use to fully unlock the power of the Grid.
  3. Next, we'll learn about the StackPanel and just for fun, we'll convert our app from a Grid layout to a StackPanel layout—this will teach us about some key differences between the Grid and StackPanel.
  4. Finally, we'll talk about how event handers are "wired up" from both XAML and in C#.

1. Understanding the Basics of Grids

The default Windows Phone Page template creates a <Grid> element called "ContentPanel".

The Grid element is used for laying out other controls ... it allows you to define rows and columns, and then each control can request which row and column they want to be placed inside of.

Now, in the default MainPage.xaml page template, between the opening and closing <Grid></Grid> tags, the Grid appears empty ... it appears that there's no rows or columns defined. However, by default, there's always one RowDefinition and one ColumnDefinition even if it's not explicitly defined, and these take up the full vertical and horizontal space available to represent one large "cell" in the Grid. Any items placed between the opening and closing <Grid></Grid> elements are understood to be inside that single implicitly defined "cell".

2. Grid RowDefinitions and ColumnDefinitions and defining sizes

An example of a Grid that actually defines rows is the "LayoutRoot" grid. The Grid defines two rows:

For now, notice how the StackPanel with the project and page titles places itself inside the first row ... the StackPanel has an attribute called Grid.Row="0". You reference both rows and columns using a zero-based numbering scheme.

Notice how the ContentPanel Grid places itself in the second row (by setting the attribute Grid.Row="1").

The first row has its height set to "Auto". The second row (row 1) is set to "*". There are three syntaxes that you can use to help persuade the sizing for each row and column. I used the term "persuade" intentionally. With XAML layout, heights and widths are relative and can be influenced by a number of factors. All of these factors are considered by the layout engine to determine the actual placement of items on the page.

For example, "Auto" means that the height for the row should be tall enough to accommodate all of the controls that are placed inside of it. If the tallest control is 150 pixels tall, then that's the actual height of the row. If it's only 100 pixels, then THAT is the height of the row. Therefore, "Auto" means the height is relative to the controls inside of the row.

The asterisk is known as "star sizing" and means that the height of the row should take up all the rest of the height available.

Here's a quick example of another way to use "star sizing" ... I created a project that has three rows defined in the ContentPanel. Notice the heights of each one:

Putting a number before the asterisk, I'm saying "Of all the space available, give me 1 or 2 or 3 shares of the remainder". Since the sum of all those rows adds up to six, each 1* is equivalent to 1/6th of the height available. Therefore, 3* would get half of the height available as depicted in the output of this example:

Besides Auto and star sizing, you can also specify widths and heights (as well as margins) in terms of pixels. In fact, when only numbers are present, it represents that number of pixels. Generally, it's not a good idea to use exact pixels in layouts for widths and heights because of the likelihood that screens—even Windows Phone screens—can have different dimensions. Instead, it's preferable to use relative values like Auto and star sizing for layout.

One thing to note from this example (and from our original PetSounds example) is that control widths and heights are assumed to be 100% unless otherwise specified. That's why the rectangles take up the entire "cell" size. This is why the button first occupied the entire ContentPanel grid, and why I had to specify I wanted the button to be 200 x 200 pixels instead.

I want to also point out that a Grid can have a collection of ColumnDefinitions as you can see from this example app I created called GridsRowsAndColumns. Here we have a 3 by 3 grid:

... the result is a simple grid with a number in each "cell":

The other thing I want you to notice about this example is that when you don't specify a Grid.Row or Grid.Column, it is assumed to mean the first row (row 0) or first column (column 0). Relying on the defaults keeps your code more concise.

3. Grid cell Alignments and Margins

I have another example app called AlignmentAndMargins. This XAML:

Produces this result:

Most of this example should be obvious if you stare at it for a few moments, but there are several finer distinctions I want to make about Alignments and Margins. First, it points out how VerticalAlignment and HorizontalAlignment work, even in a given Grid cell (and the same will hold true in a StackPanel as well). The ___Alignment attributes PULL controls TOWARDS their boundaries. By contrast, the Margin attributes PUSH controls AWAY from their boundaries. The second observation is the odd way in which Margins are defined ... as a series of numeric values separated by commas. This convention was borrowed from Cascading Style Sheets. The numbers represent the margin pixel values in a clock-wise fashion starting from the left side. So,

Margin="10,20,30,40"

Means, 10 pixels from the left boundary, 20 pixels from the top boundary, 30 pixels from the right boundary, 40 pixels from the bottom boundary. In this case, the boundary is a single Grid cell (since the Content panel only has not defined any additional RowDefinitions and ColumnDefinitions).

A bit earlier I said that it's generally a better idea to use relatives sizes like Auto and * to define heights and widths ... why, then, are margins are defined using pixels? Margins are expressed in exact pixels because they are usually just small values to provide spacing or padding between two relative values and can therefore be a fixed value without negatively impacting the overall layout of the page.

4. StackPanel basics

The second style of layout is enabled by using the StackPanel element. It will arrange your controls in a flow from top to bottom.

Back in our PetSounds project, we have the following StackPanel defined to create the app title and page title at the top of the MainPage.xaml:

Both TextBlock elements take up the entire horizontal width of their parent (the LayoutRoot Grid) and therefore they are stacked vertically. Let's convert our ContentPanel:

from a Grid into a StackPanel:

At first, this conversion only moves the Meow Button vertically downward:

However, if I were to remove the Width and HorizontalAlignment attributes from the Quack button (I also remove the Button.Background property):

And comment out the Width and HorizontalAlignment attributes from the Meow button ... AND comment out the Margin in my MainPage() constructor:

Then you could see that the two buttons are vertically stacked in the StackPanel:

 

So, as you can see, you can achieve just about any layout you can imagine by using a combination of four things:

  • Grid layout, including RowDefinitions and ColumnDefinitions
  • StackPanel layout
  • Margins to move elements away from the left-side, top-side, right-side or bottom-side
  • The HorizontalAlignment and VerticalAlignment attributes

Ok, so that's XAML Layout in a nutshell. Let's move on to events.

5. Understanding Events

If you watched the C# Fundamentals series on Channel9, in one of the last videos we talked about events. In the Windows Phone API, Pages and Control raise events for key moments in their lifecycle OR for interactions with the end user. In this series, we've already "wired up" the Click event of our PlayAudioButton with a method that I called an "event handler". When I use the term "event handler" I'm merely referring to a method that is associated with an event. I use the term "wired up" to mean that the event is tied to a particular event handler method. Some events events can be triggered by a user, like the Click event of a Button control. Other events happen during the lifetime of an event, like a Loaded event that occurs after the given Page or Control object has been instantiated by the Phone APIs Runtime engine.

There are two ways to "wire up" an event for a Page or Control to an event handler method. The first is to set it using the attribute syntax of XAML. We've already done this in our PlayAudioButton example:

If you'll recall, we typed:

Click="

And before we typed in the closing double-quotation mark, Intellisense asked if we wanted to select or create an event handler. We told it we wanted to create a new event handler, and Visual Studio named the event handler using the naming convention:

NameOfElement_EventName

... so in our case ...

PlayAudioButton_Click

Visual Studio also created a method stub in the code-behind for the XAML page, in our case, the MainPage.xaml.cs. Keep in mind that these are Visual Studio automations. We could have hit the escape key on the keyboard when Intellisense first popped up and typed that code in by hand.


A second way to associate an event with an event handler is to use the Properties window in Visual Studio:

 

(1) First, you must make sure you've selected the Control you want to edit by placing your mouse cursor in that element. The name of that element will appear in the Name field at the top letting you know the context of the settings below. In other words, any settings you make will be to the PlayAudioButton as opposed to another control on the page.

(2) Click the lightening bolt icon. This will switch from a listing of Properties / attributes that can be changed in the Properties window to the Events that can be handled for this Control.

(3) Double-click on a particular textbox to create an association between that Control's event and an event handler. Double-clicking will automatically name the event and create a method stub for you in the code behind.

The third technique (that we'll use several times in this series) is to wire up the event handler in C# code. See line 35 below for an example:

 

The += operator can be used in other contexts to mean "add and set" ... so:

x += 1;

... is the same as ...

x = x + 1;

The same is true here (in a sense) ... we want to "add and set" the Click event to one more event handler method. Yes, the Click event of myButton can be set to trigger the execution of MULTIPLE event handlers! Here we're saying "When the Click event is triggered, add the PlayAudioButton_Click event handler to the list of event handlers that should be executed." One Click event could trigger on or more methods executing. In our app, I would anticipate that only this one event handler, PlayAudioButton_Click, would execute.

You might wonder: why doesn't that line of code look like this:

myButton.Click += PlayAudioButton_Click();

Notice the open and closed parenthesis on the end of the _Click. Recall from the C# Fundamentals series ... the () is the method invocation operator. In other words, when we use () we are telling the Runtime to EXECUTE the method on that line of code IMMEDIATELY. That's NOT what we want in this instance. We only want to associate or point to the PlayAudioButton_Click method.

One other interesting note about event handler methods. With my addition of line 35 in the code above, I now have two events both pointing to the same event handler method PlayAudioButton_Click. That's perfectly legitimate. How, then, could we determine which button actually triggered the execution of the method?
If you look at the definition of the PlayAudioButton_Click method:

private void PlayAudioButton_Click(object sender, RoutedEventArgs e)
{

}

The Windows Phone Runtime will pass along the sender as an input parameter. Since we could associate this event with any Control, the sender is of type Object (the type that virtually all data types in the .NET Framework ultimately derive from), and so one of the first things we'll need to do is do a few checks to determine the ACTUAL data type (Are you a Button control? Are you a Rectangle control?) and then cast the Object to that specific data type. Once we cast the Object to a Button (for example) then we can access the Button's properties, etc.

The method signature in the code snippet above is typical of methods in the Windows Phone API. In addition to the sender input parameter, there's a RoutedEventArgs type used for those events that pass along extra information. You'll see how these are used in advanced scenarios, but I don't believe we'll see them used in this series.

Recap

To recap, the big takeaways in this lesson are the ways in which we can influence the layout of Pages and Controls.  With regards to Grid layout we learned about the different ways to define the heights and widths of Rows and Columns (respectively) using Auto sizing, star sizing and pixel sizing. We talked about how VerticalAlignment and HorizontalAlignment pull controls towards boundaries while Margins push Controls away from boundaries. Then we talked about the different ways to wire up events to event handler methods, and the anatomy of an event handler method's input parameters.

Tags:

Follow the Discussion

  • Good lesson

  • Great tutorial!

  • Shen ZhongweiShen Zhongwei

    'Margins are expressed in exact pixels because they are usually just small values to provide spacing or padding between two relative values ...' My question is: do relative values really mean relative ITEMS? Thanks.

  • @Shen Zhongwei: Admittedly, I could have said that more cleanly, but I actually did mean "relative values" there.  In other words ... a padding / margin value is expressed as a pixel value because it pads / provides a margin for two widths / heights belonging to two objects (in this example, Rectangle objects, but it could be text boxes, pictures, etc.)  Example: the phone has a fixed width on its screen, but different phones have different fixes widths.  I can specify that two Rectangles on my form should take up half (50%) of the width ... BUT ... I want some padding between the Rectangles so you can see two "boxes", not one.  In order for the layout manager to decide how much width to give each Rectangle, it has to know the overall width minus any fixed widths for margin / padding.  Now that it knows the ABSOLUTE widths, it can calculate the RELATIVE widths. 

    I suppose the designers of the layout manager could have said you could create relative widths for padding and margin and they could still do some calculations to figure out some equitable way to split all that width between the rectangles and margin / padding, but they didn't.  So, what I said was a bit clumsy, but still accurate.

  • Shen ZhongweiShen Zhongwei

    I see, the "relative values" belong to two rectangles. Thank you.

  • khaled fareskhaled fares

    thanks. i hope you attach the subtitles so that we can focus on the tutorial point instead of the language :)

  • Hey Bob,

    Thanks for another awesome video from you!. I've been following your video lessons for quite some time already (since your C# Tutorial).

    I have a question regarding your "challenge" at the end of your video.

    For MainPage.xaml, I added these lines of code:

    <MediaElement x:Name="MeowMediaElement"
    Source="/Assets/Audio/Animals/Cat meow.wav"
    AutoPlay="False"
    Volume="1"
    />
    

    For MainPage.xaml.cs, I added these lines of code:

    myButton.Click += myButton_Click;
    
    void myButton_Click(object sender, RoutedEventArgs e)
            {
                MeowMediaElement.Play();
            }

    I don't think this is "simple" enough, but it works! My question is: Is there any simpler way than this code?

    Once again, I want to say that I really enjoyed your series. Thank you so much!

    ~Josh

  • Clint RutkasClint I'm a "developer"

    @jsaliutama: to make it simpler, you can do the Click event wire up in XAML.  example: <Button Click="myButton_Click">foo</Button>

  • EkeEke

    Just out of curiosity, what would happen, if I did:

    myButton.Click = PlayAudioButton_Click; or
    myButton.Click -= PlayAudioButton_Click;

    In the first case my main question is that, would I override some default events associated with button?

  • Clint RutkasClint I'm a "developer"

    @Eke: you can't do a straight = since event handlers.  You can assign multiple handlers to a single event.  So to add them, you do +=, just like integers.  To remove them, you do -=. 

  • Thanks a lot! Your videos really help! I am a senior school student and I was troubled by not finding good tutorial until I watched this great series! Very much thanks!

  • StoyanStoyan

    Im a pascal fan, but on Event handler

    if (sender as TObject).name = 'MeowMediaElement' ;
    then MediaElement.File = '....'; // 1
    if (sender as TObject).name = 'QuackMediaElement'
    then MediaElement.File = '....'; // 2

    MeowMediaElement.Play();

  • KeithKeith

    I have learned more from these lessons then months of trying to find and follow other examples. These are very helpfull and I would like to see more.

  • @loveran: Very cool!  Good luck to you!

    @Keith: Wow.  Thank you for that nice note.  Smiley

  • Hi Bob,

    I have learn to write C# cod from Your Tutorial, 

    It Was Ossam Thank You for that.

  • Hoi TranHoi Tran

    thanks Bob!

  • A2ZA2Z

    Thanks Bob for this wonderful tutorial.

  • Bhushan FiskeBhushan Fiske

    Thanks for posting this tutorial. Its realy helps to learn basic of XAML.

  • AzizAziz

    How can I write += for buttons that I have created using XAML?

  • @Aziz: Give the XAML control a name attribute.  Reference the XAML control by name in your C# code ... probably want to do that in Window_Load or whatever its called.  Good luck.

  • @BobTabor:i have a problem when change "Grid" for "StackPanel", the button in C# disappear and the button in the XAML is ok
    I use System.Windows.HorizontalAlignment.Right for mybutton
     

  • @robalino: Please post your code.

  • @BobTabor:i have this button in the xaml

    <Button Name="PainkillerButton"
    Height="100"
    Width="200"
    HorizontalAlignment="Left"
    VerticalAlignment="Top"
    Click="PlayAudioButton_Click"
    Content="Painkiller">
    <Button.Background>
    <RadialGradientBrush>
    <GradientStop Color="Black" Offset="1"/>
    <GradientStop Color="Red"/>
    </RadialGradientBrush>
    </Button.Background>
    </Button>

    and this in the .cs

    Button myButton = new Button();
    myButton.Name="LeatherRebelButton";
    myButton.Height = 100;
    myButton.Width = 200;
    myButton.HorizontalAlignment = System.Windows.HorizontalAlignment.Right;
    myButton.VerticalAlignment = System.Windows.VerticalAlignment.Top;
    myButton.Background = new SolidColorBrush(Colors.Red);
    myButton.Content="Leather Rebel";
    ContentPanel.Children.Add(myButton);


    if i put the content Panel like "Grid", it's ok, but if i change "Grid" for "StackPanel" the button in the .cs disappears

    PD: i don't have pets's sounds so i used music Smiley

  • @robalino: Right, because in a StackPanel, the content has to be embedded in the opening / closing tags for it to work. I don't have VS open at the moment, but you probably need to revise last line of C# to MyStackPanelName.Children.Add(myButton) for that to work.  Just a guess ...

  • thanks, the problem was resolved

  • GoranGoran

    Hello everyone! I have a problem, can anyone help me? I added more pet sounds in my app, but media element wont play the sound for those on the bottom of the list. It plays normally the ones which are shown when I start the app, but when I scroll down to the bottom it wont play sound for them. Any ideas how could i fix this problem? Thanks in advance!

  • YogeshYogesh

    Hi All,
    I tried to get the contact group details stored in windows phone 8,but i failed can you help me out.I am able to read the contact details but not group.

  • Hi Bob,

    Nice videos.

    One quick question for the Part 5: Basics of Layout and Events video, around 09:10 when you have created a 9 cell grid and placed text within each cell.

    As all controls expand to fill up the space unless specified otherwise, why didn't the textblock did so?

     

     

  • @RainMakerQuark: That's a really good question.  I'm not 100% sure, but I *think* it is because there's a default style on the text.  I could override that style by adding the following:

    <Page.Resources>

    <Style TargetType="TextBlock">

    <Setter Property="FontSize" Value="42" />

    </Style>

    </Page.Resources>

     

  • @BobTabor:Hi,Bob it's a nice video

    I have a similar question as RainMakerQuark just said.If i declar a button like this:

    <Button name="btn" Content="A Button" FontSize="0.5*" />

    As we known, FontSize="0.5*" is wrong code,but i want the FontSize Attribute works as the Grid. I wish the FontSize changing with the phone's screen size, not a fixed value.I don't know how to do it.

    ps:My English is not good, hoping you know what i mean.

    Thanks a lot.

  • thanks, your tutorial is easy to understand

  • Great tutorials, nicely paced and easy to understand.  The Microsoft way of doing things is slightly different in my experience to other platforms, Android etc so good to have the mechanics of it explained.

    A note though, I'm following these having upgraded to windows phone 8.1 using VS2013 Ultimate and quite a bit of the behaviour of the XAML especially, doesn't seem to be the same any more.  For example, it is necessary to set HorizontalAlignment to Stretch for the control to fill the StackPanel control width.

    Button myButton = new Button();
    myButton.Name = "MeowButton";
    myButton.VerticalAlignment = VerticalAlignment.Stretch;
    myButton.HorizontalAlignment = HorizontalAlignment.Stretch;
    myButton.Background = new SolidColorBrush(Colors.Red);
    myButton.Content = "Meow";
    
    ContentRoot.Children.Add(myButton);

    It seems the Vertical and Horizontal Alignment enums have also moved to Windows.UI.Xaml.VerticalAlignment from System.Windows.

    Hopefully this could help anyone trying to follow through using wp8.1 not 8 for the basics of XAML and C# as I am.

    Thanks

  • Very Nice and User Friendly tutorials.Thanks.JazakALLAH :)

     

  • But i Couldn't exactly get about StackPannel 

  • PhantompigPhantompig

    Hi
    When I change my content panel from a grid to a stackpanel and remove the Height and Alignment properties for my button it does not fill to the right. This should be inheriting this width from its parent?

    Here is my code, I am using the libraries for Windows 8.1. Could there be some default in here stopping it, or am I missing the obvious?

    <Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
    <RowDefinition Height="Auto"/>
    <RowDefinition Height="*"/>
    </Grid.RowDefinitions>

    <!--Title Panel contains the name of the application and the page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
    <TextBlock Text="MY APP" Style="{StaticResource BaseTextBlockStyle}" Margin="12,0"/>
    <TextBlock Text="Page Name" Margin="9,-7,0,0" Style="{StaticResource HeaderTextBlockStyle}"/>
    </StackPanel>

    <!--Content Panel-->
    <StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Button Name="PlayAudioButton"
    Width="200"
    VerticalAlignment="Top"
    Click="PlayAudioButton_Click"
    Background="Red">

    Quack
    </Button>
    <MediaElement x:Name="QuackMediaElement"
    Source="/Assets/Audio/Animals/Duck.wav"
    Volume="1.0"
    AutoPlay="False"
    />
    </StackPanel>

    </Grid>

    Any ideas?

  • PhantompigPhantompig

    Sorry in that last post I forgot to remove the Width="200"

    I was playing around to check the defaults, please ignore that line. The problem is still there without it.

  • BasavaBasava

    Nice Tutorial for beginner's Thanks a lot...

  • @Basava:Basava! This tutorial is really very cool for beginners, for example for me. Thanks a lot.

  • @Phantompig: About "in that last post I forgot to remove the Width="200"". The problem is really still there without it.

  • MateoMateo

    I really like your Mario Bros.

  • Hi Bob Tabor, Thaaaaaaaaaaaaaaaaank you so much for your clean and deep understanding of what beginners need and your clean accent too ^_^ ... Thanks again

  • VrushankVrushank

    hello,
    i just put a button on main page of App.
    Now i want that when i click on this button the next page will be come.
    plz give me the solution.

    this is main-page.xmal.cs code for button

    private void Button_Click_3(object sender, RoutedEventArgs e)
    {

    }

  • GajendraGajendra

    i m havin problem to show images in gridview.
    please suggest what should i do and how should do..???

  • ObaidObaid

    Dear,
    I have buttons on the screen, and all the button doesn't set completely to its edges. What is the process or windows mobile doesn't support the full stretch of button images?

    Error Image link:
    http://stackoverflow.com/questions/26970796/windows-mobile-button-not-filling-the-edges?noredirect=1#comment42507316_26970796

Remove this comment

Remove this thread

close

Comment on the Post

Already have a Channel 9 account? Please sign in