Windows 8 XAML Layout Issues - anchor control on right side of screen - xaml

I'm struggling to understand how the xaml controls can help me accomplish the following layout:
I have a 3-column layout. The leftmost and center columns have listviews. The rightmost column simply has a clickable (tappable) stackpanel that navigates elsewhere. I want this stackpanel to be anchored to the right side of the page, halfway down (i.e. in CSS I would say right: 0, top: 50%).
My XAML is below. My strategy has been to create a horizontal parent stackpanel containing all 3 columns, and a vertical stackpanel with a textblock on top of a listview control in the leftmost and middle columns. However, the third stackpanel behaves in some unexpected ways:
It does not fill the horizontal space remaining to the right of the second stack panel. It seems to prefer to only take up the space required by whatever its child controls require. This means that I have to assign static values to child elements to try to line the clickable control up with the right side of the page. This means that when screen resolutions are different than what I'm designing for, this clickable control will be either off the right side of the page, or toward the middle of the page.
I can't coerce the clickable element in the third column (stackpanel, or any other control I try to use) to move halfway down the page. As I mentioned above, I want it to be halfway down the page, but it stubbornly sits at the top of its containing stackpanel.
I've looked at the canvas control, but don't want this to be static - this is so easy in CSS, I'm not sure why it's so complicated in XAML.
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1160"/>
<ColumnDefinition Width="206"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Back button and page title -->
<Grid Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="pageTitle" Grid.Column="1" Text="{StaticResource AppName}" Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
<StackPanel Orientation="Horizontal" Grid.Row="1" HorizontalAlignment="Stretch" Grid.ColumnSpan="2">
<StackPanel
Orientation="Vertical"
Margin="0,0,40,0">
<StackPanel
Height="100"
Width="400"
HorizontalAlignment="Left"
Margin="40,15,0,0">
<StackPanel.Background>
<SolidColorBrush>
<Color>#FFFFFF</Color>
</SolidColorBrush>
</StackPanel.Background>
<TextBlock
Text="Announcements"
FontSize="42"
FontWeight="Light"
TextAlignment="Left"
Padding="0,25,25,25">
</TextBlock>
</StackPanel>
<ListView
HorizontalAlignment="Left"
Height="475"
Margin="40,15,0,0"
VerticalAlignment="Top"
Width="400"
ItemsSource="{Binding Incidents}"
IsItemClickEnabled="True"
SelectionMode="None"
ItemTemplate="{StaticResource Standard130ItemTemplate}"
ItemClick="Item_Click" >
</ListView>
</StackPanel>
<StackPanel
Orientation="Vertical"
Margin="40,0,0,0">
<StackPanel
Height="100"
Width="600"
HorizontalAlignment="Right"
Margin="0,15,40,0">
<StackPanel.Background>
<SolidColorBrush>
<Color>#FFFFFF</Color>
</SolidColorBrush>
</StackPanel.Background>
<TextBlock
Text="News from Yammer"
FontSize="42"
FontWeight="Light"
TextAlignment="Left"
Padding="0,25,25,25">
</TextBlock>
</StackPanel>
<ListView
HorizontalAlignment="Left"
Height="475"
Margin="40,15,0,0"
VerticalAlignment="Top"
Width="Auto"
ItemsSource="{Binding Incidents}"
IsItemClickEnabled="True"
SelectionMode="None"
ItemTemplate="{StaticResource Standard130ItemTemplate}"
ItemClick="Item_Click" >
</ListView>
</StackPanel>
<StackPanel Background="AliceBlue" Width="206" Height="628">
<TextBlock x:Name="stackPanel" Background="Black" Height="50" Width="20" HorizontalAlignment="Right" Margin="10,100,10,0" Opacity="0"/>
</StackPanel>
</StackPanel>

StackPanels only give enough space to their child elements as the need. I would recommend the following:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center">
<!-- Right most column -->
</StackPanel>
</Grid>
This was the stack panel stretches to fit the column.

Related

How to dynamically update ListView height while keeping the ScrollViewer enabled?

ListView is placed inside UserControl which is set in parent XAML to asterix "*" height.
I want to use ListView with possibility to scroll items, when there are items that exceed ListView. It should work for different size of window.
It works fine when I set Grid's RowDefinitions with fixed integer, but when I try to use asterix "*" ScrollViewer disables.
I also tried to bind and update RowDefinition's height via some code behind in overriden MeasureOverride method, but it didn't work as expected.
Here is code inside my UserControl:
<Grid x:Name="ContentArea"
Background="{StaticResource MixerBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="{x:Bind ListViewHeight}" />
</Grid.RowDefinitions>
<ListView
ItemsSource="{x:Bind ViewModel.Source,Mode=TwoWay}"
CanDragItems="True"
CanReorderItems="True"
AllowDrop="True"
SelectionMode="Single"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.ItemTemplate>
<DataTemplate x:DataType="models:Track">
<Grid
Background="LightGray"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
BorderBrush="Black">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<TextBlock
Text="{x:Bind Id}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontSize="24"
Margin="20,5,20,5"/>
<Grid
Background="Black"
Width="500"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Column="1">
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I expect to get the ScrollViewer working correctly, but ListView stay at the old size or scroll bar is disabled - depending on Height value.
Is there any way to achieve dynamically resizing ListView with scroll?
Edit
Here is parent Page XAML code which is loaded into Frame via Light MVVM framework:
<Grid
x:Name="ContentArea">
<Grid
Background="{ThemeResource SystemControlPageBackgroundChromeLowBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="100" />
<RowDefinition Height="*" />
<RowDefinition Height="300" />
</Grid.RowDefinitions>
<maineditor:MainEditorMenuControl x:Name="ProjectMenu" />
<maineditor:MainEditorWorkspaceControl x:Name="Workspace" Grid.Row="1"/>
<maineditor:MainEditorMixerControl x:Name="Mixer" Grid.Row="2" />
</Grid>
</Grid>
Edit 2
I think the problem may be connected with MVVM template I've created with Windows Template Studio plugin for Visual Studio. If I try to recreate minimal solution from scratch with all properties 1:1 as in my app it works in fresh project, but not in mine.
How to dynamically update ListView height while keeping the ScrollViewer enabled?
If you want make RowDefinition height same as the ListView, you could give the ListView a name and use {Binding ElementName=MyListView,Path=ActualHeight}syntax to bind both height property.
<Grid x:Name="ContentArea">
<Grid.RowDefinitions>
<RowDefinition Height="{Binding ElementName=MyListView,Path=ActualHeight}" />
</Grid.RowDefinitions>
<ListView
Name="MyListView"
CanDragItems="True"
CanReorderItems="True"
AllowDrop="True"
Loaded="MyListView_Loaded"
SelectionMode="Single"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.ItemTemplate>
<DataTemplate >
<Grid
Background="LightGray"
HorizontalAlignment="Left"
VerticalAlignment="Stretch"
BorderBrush="Black">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>
<TextBlock
Text="{Binding}"
VerticalAlignment="Center"
HorizontalAlignment="Center"
FontSize="24"
Margin="20,5,20,5"/>
<Grid
Background="Black"
Width="500"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Grid.Column="1">
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>

Why is there empty space at the top & bottom of my page when the UWP app runs? XAML nor Design view shows empty space

Why does my UWP (Universal Windows Platform) App force extra space at the top and bottom of my app even though there is nothing there?
Here's what it looks like:
Even though in Visual Studio 2013 (design mode) you can see that the blue bounding box displays the bottom of the page as follows:
The outer grey is the device it would be running on.
The XAML looks like the following:
<Page
x:Class="CYaPass.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:CYaPass"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Height="515" Width="570" Background="LightGray" Loaded="Page_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="320"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Grid.Row="0">
<TextBlock FontSize="16" HorizontalAlignment="Center">1. Select a Site/Key</TextBlock>
<ListView BorderThickness="2" BorderBrush="Aquamarine"
x:Name="SiteListBox" HorizontalAlignment="Stretch" VerticalAlignment="Center" Height="251"
Margin="10,10,0,0" Width="Auto" SelectionChanged="SiteListBox_SelectionChanged">
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Padding" Value="5,0,0,0" />
</Style>
</ListView.ItemContainerStyle>
<ListViewItem Content="Item 2"/>
</ListView>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal" Grid.Column="0">
<Button x:Name="DeleteSiteButton" Content="Delete Site"
HorizontalAlignment="Right" Margin="0,0,0,0" VerticalAlignment="Top" Click="DeleteSiteButton_Click"/>
<Button x:Name="AddSiteButton" Content="Add Site" HorizontalAlignment="Right"
Margin="10,0,0,0" VerticalAlignment="Top" Click="AddSiteButton_Click"/>
</StackPanel>
</StackPanel>
<TextBox x:Name="passwordTextBox" HorizontalAlignment="Left" Margin="7,150,0,0" Grid.Row="1" Grid.ColumnSpan="2"
TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="560"/>
<StackPanel HorizontalAlignment="Left" Height="128" Margin="10,0,0,0" Grid.Column="0" Grid.Row="1"
VerticalAlignment="Top" Width="285">
<Grid Margin="0,0,-11,0">
<Grid.RowDefinitions>
<RowDefinition Height="40" ></RowDefinition>
<RowDefinition Height="40" ></RowDefinition>
<RowDefinition Height="40" ></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="180"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<CheckBox x:Name="addUppercaseCheckbox" Grid.Row="0" Grid.Column="0" Content="Add Uppercase" HorizontalAlignment="Stretch" VerticalAlignment="Center" Width="254" Click="addUppercaseCheckbox_Click" Margin="7,0,3,0"/>
<CheckBox x:Name="addSpecialCharscheckBox" Grid.Row="1" Grid.Column="0" Content="Add Special Chars" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="7,0,3,0"/>
<TextBox x:Name="specialCharsTextBox" Grid.Column="1" Grid.Row="1" Margin="7,0,3,0" VerticalAlignment="Center" HorizontalAlignment="Stretch" Grid.RowSpan="1" TextWrapping="NoWrap" Text="#"/>
<CheckBox x:Name="setMaxLengthCheckBox" Grid.Row="2" Grid.Column="0" Content="Set Max Length" HorizontalAlignment="Stretch" VerticalAlignment="Center" Margin="7,0,3,0"/>
<local:NumericUpDown Grid.Column="1" HorizontalAlignment="Left" Margin="7,0,3,0" Grid.Row="2" VerticalAlignment="Center" Width="64"/>
</Grid>
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="0">
<TextBlock Grid.Column="1" Grid.Row="0" FontSize="16" HorizontalAlignment="Center">2. Draw a pattern</TextBlock>
<Canvas HorizontalAlignment="Center" x:Name="MainCanvas"
Height="252" Width="252" Margin="7,10,0,0" VerticalAlignment="Top" Background="AliceBlue" Tapped="MainCanvas_Tapped" PointerMoved="MainCanvas_PointerMoved"/>
<Button x:Name="ClearGridButton" Content="Clear"
Margin="50,0,10,0" VerticalAlignment="Center" Click="ClearGridButton_Click" HorizontalAlignment="Right"/>
</StackPanel>
</Grid>
</Page>
You can see the page's width is wider than the height, but when the app runs on a desktop or a simulator device (like 7" pad) the extra space is pushed into the top and the bottom.
UWP Forced Minimum?
Is this due to some minimum size or something that UWP forces on apps?
Cannot Resize Smaller When Running
Even if I grab the form's bottom or top bounding frame when the app is running, I cannot make it any smaller.
The Default Content-Alignment is set to Center because you set the Height and Width of your Page, so your page is placed in the Center and isn't filling the whole Screen.
One Possible Solution is to add to the Page xaml Attributes this Piece of Code:
VerticalAlignment="Top".
To set the HorizontalAlignment to the left add this:
HorizontalAlignment="Left".
One more advise: When you don't Need to Display more than one xaml Page at the Screen leave the Page Height and Width to Default.

How to use full width of Phone in xaml?

I have 3 controls in a Grid.Row but how can I make them use the full width of the page?
This is my xaml:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="140" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
Grid.Row="1"
Source="/Assets/image1.png"
Height="25"
Width="25" />
<TextBox Grid.Column="1"
Margin="10,0,0,0"
Text="{Binding InputText, Mode=TwoWay}"
BorderBrush="Black"
BorderThickness="2"
VerticalAlignment="Center">
</TextBox>
<Button Grid.Column="2"
BorderThickness="2"
HorizontalAlignment="Right"
Command="{Binding AddTextCommand}"
Margin="10,0,0,0">
<TextBlock x:Uid="ButtonText" />
</Button>
</Grid>
This is now the result:
As you can see it is aligned left, how can I make it use the full width?
You're code only shows 3 controls (Image, TextBox, Button), while your screenshot gives 4 controls. I suppose the full width control on top is missing, but that's no problem to answer the question.
If we break down your XAML, you have:
First column width Auto, filled with an image.
Second column width 140, filled with a TextBox
Third column width * (or the rest of the space), filled with a Button
On the button you have placed HorizontalAlignment="Right" (default is Left), in which you're saying: only use the space necessary and put the control on the right side. If you want to use the full width available, you have to use HorizontalAlignment="Stretch".
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="140" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0"
Source="/Assets/image1.png"
Height="25"
Width="25" />
<TextBox Grid.Column="1"
Margin="10,0,0,0"
Text="{Binding InputText, Mode=TwoWay}"
BorderBrush="Black"
BorderThickness="2"
VerticalAlignment="Center">
</TextBox>
<Button Grid.Column="2" x:Uid="ButtonText"
BorderThickness="2"
HorizontalAlignment="Stretch"
Command="{Binding AddTextCommand}"
Margin="10,0,0,0" />
</Grid>
Note that I have also removed the TextBlock from the Button and move the x:Uid tag to the button. Simply use ButtonText.Content in your resources to have your button localized, there's no need to place a TextBlock in there.

Grid inside button won't stretch horizontally

Given the following markup, I would have expected the chevron to go all the way to the right of the button, but it doesn't - instead, the stack panel and the chevron are tight together in the middle of the button.
<Button Background="Teal" HorizontalAlignment="Stretch">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel HorizontalAlignment="Stretch"
Grid.Column="0">
<TextBlock HorizontalAlignment="Center"
TextAlignment="Center"
FontSize="60">Click!</TextBlock>
<TextBlock HorizontalAlignment="Stretch"
TextAlignment="Center"
FontSize="20">Cool things will happen</TextBlock>
</StackPanel>
<TextBlock Grid.Column="1"
FontSize="60"
FontFamily="Segoe UI Symbol">
 <!-- unicode for chevron right in this font -->
</TextBlock>
</Grid>
</Button>
You can try to set the HorizontalContentAlignment of the button to Stretch.

XAML element inside of ItemsControl DataTemplate sometimes has null parent (WinRT)

I'm making a win8 app. I have an ItemsControl with a DataTemplate. Inside this DataTemplate, there is a Grid. Inside this Grid there is a WebView and a ProgressRing. I have an event for LoadCompleted on the WebView, at which time I want to disable the ProgressRing. My thought was to use the following:
ProgressRing pr = ((sender as FrameworkElement).Parent as Grid).Children.First(t => t.GetType().Equals(typeof(ProgressRing))) as ProgressRing;
pr.IsActive = false;
And this works sometimes, but sometimes it claims that ((sender as FrameworkElement).Parent) is null. I verified from debugging that in these cases, the sender is still the correct WebView. The WebView is being shown on the screen and is formatted correctly - so how could its parent be null?
Here's the XAML:
<ItemsControl Margin="40,0,40,0" x:Name="resultsItemsControl">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"></StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="50,0">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="30"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" MaxWidth="150"></ColumnDefinition>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="100" MaxWidth="100"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="viewInBrowser" IsEnabled="False" Style="{StaticResource PreviewLinkAppBarButtonStyle}" Margin="0,0,40,0" Click="viewInBrowser_Click_1"></Button>
<TextBlock HorizontalAlignment="Left" TextAlignment="Left" Grid.Column="1" FontSize="30" Margin="0,20,0,20" FontWeight="Bold" FontFamily="Georgia" VerticalAlignment="Center" Text="{Binding Name}"></TextBlock>
<ProgressRing x:Name="loadingProgressRing" Margin="20,0" Grid.Column="2" Foreground="White" IsActive="True" HorizontalAlignment="Left" VerticalAlignment="Center"></ProgressRing>
<WebView ScriptNotify="WebView_ScriptNotify_1" Grid.Column="0" Grid.ColumnSpan="14" Grid.Row="1" Source="{Binding CurrentSearchUrl}" Width="0" LoadCompleted="WebView_LoadCompleted_1"></WebView>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I wouldn't use a WebView in an ItemsControl at all, but you could try putting your entire template in a UserControlm then you handle the event inside of the UserControl and don't need to care about sender, since you can just name the Grid and access a named Grid.