Make ScrollViewer fill dynamic area - wpf

In the example below I cannot get the ScrollViewer to fill the space available, The height is unknown due to the dynamic content above but is there no way it can fill the space available instead of over running?
<Grid x:Name="Main" Height="200" MaxHeight="200">
<StackPanel>
<Grid x:Name="MainContent" Height="170" MaxHeight="170">
<StackPanel>
<TextBlock FontSize="24" Text="Dynamic data "/>
<TextBlock FontSize="24" Text="height "/>
<TextBlock FontSize="24" Text="unknown... "/>
<Grid x:Name="Results" Background="Red">
<ScrollViewer>
<StackPanel>
<TextBlock FontSize="24" Text="Result set... 0"/>
<TextBlock FontSize="24" Text="Result set... 1"/>
<TextBlock FontSize="24" Text="Result set... 2"/>
<TextBlock FontSize="24" Text="Result set... 3"/>
</StackPanel>
</ScrollViewer>
</Grid>
</StackPanel>
</Grid>
<Grid x:Name="Nav">
<Button HorizontalAlignment="Left" Content="Back"/>
<Button HorizontalAlignment="Right" Content="Forward"/>
</Grid>
</StackPanel>
</Grid>

in MainContent Grid use DockPanel instead of StackPanel with LastChildFill=True, something like this:
<Grid x:Name="MainContent" Height="170" MaxHeight="170">
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Top" FontSize="24" Text="Dynamic data "/>
<TextBlock DockPanel.Dock="Top" FontSize="24" Text="height "/>
<TextBlock DockPanel.Dock="Top" FontSize="24" Text="unknown... "/>
<Grid x:Name="Results" Background="Red">
<ScrollViewer>
<StackPanel>
<TextBlock FontSize="24" Text="Result set... 0"/>
<TextBlock FontSize="24" Text="Result set... 1"/>
<TextBlock FontSize="24" Text="Result set... 2"/>
<TextBlock FontSize="24" Text="Result set... 3"/>
</StackPanel>
</ScrollViewer>
</Grid>
</DockPanel>
</Grid>
then last element of DockPanel will adjust itself to available space

I solved it by adding another element for the Scrollviewer's Height to bind:
<grid Grid.row="3" x:Name="Mirror">
</grid>
<ScrollViewer Grid.row="3" Height="{Binding ElementName=uxMirror,XPath=ActualHeight}">
</ScrollViewer>

Firstly your layout is kind of a mess. Why do you need to put a StackPanel as the only child of a Grid. For the Rows? Use RowDefinitions and ColumnDefinitions when dealing with Grid
From my understanding of your layout, you can pretty much do everything you need with just a Grid and a DockPanel. When dealing with layout containers, Aim to get your layout with the "least" number of containers as "efficiently" possible. Even if it aint any real performance benefit, it helps enormously when going through someone else's code to not have redundant nesting
<Grid x:Name="Main">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
FontSize="24"
Text="Dynamic data " />
<TextBlock Grid.Row="1"
FontSize="24"
Text="height " />
<TextBlock Grid.Row="2"
FontSize="24"
Text="unknown... " />
<ScrollViewer Grid.Row="3"
Background="Red">
<StackPanel>
<TextBlock FontSize="24"
Text="Result set... 0" />
<TextBlock FontSize="24"
Text="Result set... 1" />
<TextBlock FontSize="24"
Text="Result set... 2" />
<TextBlock FontSize="24"
Text="Result set... 3" />
</StackPanel>
</ScrollViewer>
<DockPanel x:Name="Nav"
Grid.Row="4"
LastChildFill="False">
<Button Content="Back"
DockPanel.Dock="Left" />
<Button Content="Forward"
DockPanel.Dock="Right" />
</DockPanel>
</Grid>
This should give you everything your looking for. If you need to restrict Height dimensions with static values, Add them in accordingly when absolutely needed.
As for the "Nav" DockPanel, yes you can using HorizontalAlignment get your Button's positioned Left and Right and thereby not use the DockPanel, but that would go against the concept of trying to keep "one" item in a Grid cell and hence the DockPanel usage.

Related

Designing a Hamburger menu in WPF with Mahapps.Metro

Currently, I'm using a Grid of Buttons for housing keys for navigation. It's hideous, but gets the job done.
Here's the XAML chunk:
<Button x:Name="ShowMainMenu" Grid.Column="0" Margin="5" Content="Main Menu"/>
<Button x:Name="ShowReportsMenu" Grid.Column="2" Margin="5" Content="Reports"/>
<Button x:Name="Reset" Grid.Column="4" Margin="5" Content="Reset"/>
<Button x:Name="TryClose" Grid.Column="6" Margin="5" Content="Close"/>
Incidentally, I'm using Caliburn.micro, and so naming the buttons is enough to bind them to proper commands.
Now, I want them to put them in a Hamburger Menu.
What I have tried till now is this:
<Controls:HamburgerMenu >
<Controls:HamburgerMenu.ItemTemplate>
<DataTemplate DataType="{x:Type Controls:HamburgerMenuGlyphItem}">
<Grid Height="48">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Margin="12" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Glyph}" />
<TextBlock Grid.Column="1" VerticalAlignment="Center" FontSize="16" Text="{Binding Label}" />
</Grid>
</DataTemplate>
</Controls:HamburgerMenu.ItemTemplate>
<Controls:HamburgerMenu.ItemsSource>
<Controls:HamburgerMenuItemCollection>
<Controls:HamburgerMenuGlyphItem Glyph="1" Label="Main Menu" cal:Message.Attach="[Event Click] = [Action ShowMainMenu]"/>
</Controls:HamburgerMenuItemCollection>
</Controls:HamburgerMenu.ItemsSource>
</Controls:HamburgerMenu>
But it doesn't work, because Controls:HamburgerMenuGlyphItem isn't a FrameworkElement.
By the way, the transitioning view is implemented like this:
So, how can I translate my bunch of Buttons into a HamburgerMenu? I can't find proper documentation for Caliburn.micro's HamburgerMenu as well.
Well, I figured it out myself.
Here's the code:
<DockPanel>
<DockPanel.Resources>
<DataTemplate x:Key="MenuItemTemplate">
<Grid Height="48" Background="Black">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonUp">
<cal:ActionMessage MethodName="{Binding Tag}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="48"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" FontSize="25" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Segoe MDL2 Assets" Foreground="BlanchedAlmond" Text="{Binding Glyph}"/>
<TextBlock Grid.Column="1" VerticalAlignment="Center" FontSize="16" Foreground="White" Text="{Binding Label}"/>
</Grid>
</DataTemplate>
</DockPanel.Resources>
<Controls:HamburgerMenu Foreground="White" PaneBackground="#FF444444" IsPaneOpen="False" DisplayMode="CompactOverlay" OptionsItemTemplate="{StaticResource MenuItemTemplate}" ItemTemplate="{StaticResource MenuItemTemplate}">
<Controls:HamburgerMenu.ItemsSource>
<Controls:HamburgerMenuItemCollection>
<Controls:HamburgerMenuGlyphItem Glyph="M" Label="Main Menu" Tag="ShowMainMenu"/>
<Controls:HamburgerMenuGlyphItem Glyph="I" Label="Invoice" Tag="OpenInvoiceMaker"/>
<Controls:HamburgerMenuGlyphItem Glyph="R" Label="Reports" Tag="ShowReportsMenu"/>
</Controls:HamburgerMenuItemCollection>
</Controls:HamburgerMenu.ItemsSource>
<Controls:HamburgerMenu.OptionsItemsSource>
<Controls:HamburgerMenuItemCollection>
<Controls:HamburgerMenuGlyphItem Glyph="A" Label="About" Tag="About"/>
</Controls:HamburgerMenuItemCollection>
</Controls:HamburgerMenu.OptionsItemsSource>
<Controls:HamburgerMenu.Content>
<DockPanel>
<Border Background="#FF444444" DockPanel.Dock="Top">
<TextBlock x:Name="Header" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="15" Foreground="White" Text="{Binding ActiveItem.DisplayName}" />
</Border>
<ScrollViewer Grid.Row="1" CanContentScroll="True" IsDeferredScrollingEnabled="False">
<Controls:TransitioningContentControl Transition="LeftReplace" x:Name="ActiveItem" Content="{Binding ActiveItem}"/>
</ScrollViewer>
</DockPanel>
</Controls:HamburgerMenu.Content>
</Controls:HamburgerMenu>
</DockPanel>
Basically, I used EventTrigger to achieve the same functionality as a button. The rest was easy.

Put TextBlock on top of another TextBlock

I tried to implement case in which one TextBlock appears on top of another TextBlock, playing with Visibility property - but it doesn't working yet.
TextBlock are inside DockPanel:
<DockPanel Grid.Row="1" Margin="5">
<TextBlock Text="Text1" Height="20" HorizontalAlignment="Right" DockPanel.Dock="Right">
<TextBlock Text="Text2" Background="Aqua" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Visibility="{Binding IfDeviceSelected, NotifyOnSourceUpdated=True, Converter={StaticResource ResourceKey=BoolToVisibilityConverter}}" />
</TextBlock>
<TextBlock Text="#Device Focus:" Height="20" HorizontalAlignment="Right" DockPanel.Dock="Right" />
</DockPanel>
You will want to use a Grid to group these TextBlocks, DockPanel/StackPanel will not allow overlapping controls(without horrible manipulation of Margins etc)
<DockPanel Grid.Row="1" Margin="5" >
<Grid DockPanel.Dock="Right" >
<TextBlock Text="Text1" />
<TextBlock Text="Text2" Background="Aqua" Visibility="{Binding IfDeviceSelected, NotifyOnSourceUpdated=True, Converter={StaticResource ResourceKey=BoolToVisibilityConverter}}" />
</Grid>
<TextBlock Text="#Device Focus:" Height="20" HorizontalAlignment="Right" DockPanel.Dock="Right" />
</DockPanel>

textblock in user control TextWrapping not wrapping

I created user control with the textblock. But it will not wrap. This user control servers as a listboxitem.
<Grid x:Name="MainGrid" Height="Auto" Width="Auto">
<StackPanel Orientation="Horizontal">
<Image Height="50" Width="100" Stretch="Uniform" Name="image1" Source="{Binding Path=VideoImageUrl}" Margin="12,12,13,84" MouseLeftButtonDown="image1_MouseLeftButtonDown" MouseEnter="image1_MouseEnter" MouseLeave="image1_MouseLeave" />
<StackPanel Orientation="Vertical" >
<TextBlock TextWrapping="Wrap" Height="Auto" HorizontalAlignment="Left" Name="titleTextBox"
Text="{Binding Path=Title, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}"
VerticalAlignment="Center" Width="Auto" FontSize="14" FontWeight="SemiBold" />
<StackPanel Orientation="Vertical" x:Name="StackPanelDetails">
<TextBlock Height="Auto" HorizontalAlignment="Left" Name="desciptionTextBox"
TextWrapping="Wrap"
Text="{Binding Path=Desciption, Mode=OneWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}"
VerticalAlignment="Center" Width="Auto" />
<Line />
<ItemsControl x:Name="CustomItemsSource" ItemsSource="{Binding Path=LinksList}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink NavigateUri="{Binding Path=TopicUrl}" RequestNavigate="Hyperlink_RequestNavigate" >
<TextBlock Text="{Binding Path=TopicName}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</StackPanel>
</StackPanel>
</Grid>
A ListBox's default template does not automatically limit the width of its items, but instead uses a ScrollViewer, which shows a horizontal scrollbar when an item is wider than the ListBox.
You can remove the ScrollViewer by replacing the ListBox's Template:
<ListBox ...>
<ListBox.Template>
<ControlTemplate>
<StackPanel IsItemsHost="True"/>
</ControlTemplate>
</ListBox.Template>
...
</ListBox>
Another important thing to note is that a StackPanel in the top-level Grid won't properly resize the contained elements. In the following simplified example the text in the TextBlock is not wrapped because the containing StackPanel simply does not resize it as you expect:
<Grid>
<StackPanel Orientation="Horizontal">
<Image ... />
<Text TextWrapping="Wrap" Text=... />
</StackPanel>
</Grid>
This way it works as you expect:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Image ... />
<TextBlock Grid.Column="1" TextWrapping="Wrap" Text=... />
</Grid>

Making a WPF TextBox be only as wide as the room it has but expand when the space expands?

Notice how the textbox expands to the right until it has enough horizontal space to fit the content? Well I'd like it to not expand and fit the text with the space it has in the window.
If the windows expands, then the Grid.Column it's in will expand, but the textbox itself should expand to fit. Simple enough?
Any suggestions? This is my first foray into WPF and so far it's been pretty sleek.
Edit: Here's my XAML markup:
<Window x:Class="GameLenseWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="350" MinHeight="450" MinWidth="350">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="0.15*" />
<RowDefinition />
</Grid.RowDefinitions>
<Image Grid.Row="0" Stretch="Fill" Source="Image/topBarBg.png" />
<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock Text="Platform"
Foreground="White"
FontFamily="Georgia"
FontSize="15"
Margin="10"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<ComboBox x:Name="cmbPlatform"
Margin="10"
FontFamily="Georgia"
FontSize="15"
MinHeight="30"
MinWidth="140"
VerticalAlignment="Center"
VerticalContentAlignment="Center" SelectionChanged="cmbPlatform_SelectionChanged">
<ComboBoxItem>All Platforms</ComboBoxItem>
<ComboBoxItem>Playstation 3</ComboBoxItem>
<ComboBoxItem>XBox 360</ComboBoxItem>
<ComboBoxItem>Wii</ComboBoxItem>
<ComboBoxItem>PSP</ComboBoxItem>
<ComboBoxItem>DS</ComboBoxItem>
</ComboBox>
</StackPanel>
<Image x:Name="imgAbout" Grid.Row="0" Source="Image/about.png"
Height="16" HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="0 0 10 0" />
<ListBox Grid.Row="1" x:Name="lstGames" Background="#343434" Padding="5">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="120" Margin="0 10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
</Grid.RowDefinitions>
<Border BorderBrush="#202020" BorderThickness="5" CornerRadius="4" Panel.ZIndex="0">
<Image Grid.Row="0" Grid.Column="0" Source="{Binding ImageUrl}" Stretch="Fill"/>
</Border>
<StackPanel Grid.Row="0" Grid.Column="1" Margin="12 0 0 0">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Title:" FontFamily="Arial" Foreground="White"/>
<TextBlock Text="{Binding Title}" FontFamily="Arial" Foreground="White" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Release Date:" FontFamily="Arial" Foreground="White" />
<TextBlock Text="{Binding ReleaseDate}" FontFamily="Arial" Foreground="White" />
</StackPanel>
<TextBlock Text="Synopsis" FontFamily="Arial" Foreground="White" />
<TextBox Background="#454545" Text="{Binding Synopsis}" MinHeight="76" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
To get a TextBox to wrap inside a ListBox you can make the following changes:
Set the content of the listbox equal to the width of the listbox using: HorizontalContentAlignment="Stretch".
Disable the horizontal scrollbar of the listbox to prevent listbox from getting the desired size of the controls and preventing the word wrap in your textbox.
Set TextWrapping="Wrap" in the TextBox
Here is the XAML:
<ListBox Grid.Row="1" x:Name="lstGames" Background="#343434" Padding="5"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
HorizontalContentAlignment="Stretch" >
</ListBox>
<TextBox Text="{Binding Synopsis}" MinHeight="76" TextWrapping="Wrap" />
I believe you need to set the Margin property of your textbox control. In the designer, you can see little circles around each textbox (and each control when you focus them, for that matter). Click the little circle on the right side of the textbox, to make that control grow marginally with the available space in the current layout control (by clicking the circle, the margin will be added into the XAML).
I don't know if in your image you've already adjusted the window size, but with that image it appears you'll also need to set the width for your textbox.
Does this help?

Silverlight/WP7: I want to place an Button after the Listbox element which are data bound

I am fairly new to silverlight. I am developing on the windows phone platform.
I want to place a button at the end of the listbox entries which will be bound to data from the webservice (I am using a listbox template)
List item 1
List item 2
List item 3
List item 4
List item 5
List item 6
List item 7
List item 8
..Button..
I tried number of things of using grid/stackpanel etc to host the button and all my solutions place the button at the bottom of my screen instead of bottom of all the listbox entries which might span multiple screens.
XAML file I have is below. I want to add a button below the "LBoxItems"
<Grid x:Name="LayoutRoot"
Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid x:Name="ads" >
<!--TitlePanel contains the name of the application and page title-->
<StackPanel Margin="24,24,0,12"
x:Name="SearchTitle">
<StackPanel Orientation="Horizontal">
<TextBlock FontWeight="Bold"
FontSize="{StaticResource PhoneFontSizeLarge}"
Text="{Binding Location}" />
<TextBlock FontSize="{StaticResource PhoneFontSizeLarge}"
Text=" > " />
<TextBlock FontWeight="Bold"
FontSize="{StaticResource PhoneFontSizeLarge}"
Text="{Binding Category}" />
</StackPanel>
<TextBlock FontSize="{StaticResource PhoneFontSizeMedium}"
Text="{Binding Converter={StaticResource SearchHistoryItemSubTitleConverter}}" />
</StackPanel>
</Grid>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentGrid"
Grid.Row="2">
<ListBox x:Name="LBoxItems"
HorizontalAlignment="Left"
Margin="24, 0"
SelectionChanged="LBoxItems_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="{StaticResource PhoneTouchTargetOverhang}" >
<TextBlock FontSize="{StaticResource PhoneFontSizeMediumLarge}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" Foreground="{StaticResource PhoneAccentBrush}"
Text="{Binding Title.Text}" TextWrapping="Wrap" Margin="-4,20,0,0">
</TextBlock>
<TextBlock Text="{Binding PublishDate, Converter={StaticResource ItemPublishDateConverter}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
<l:SpinnerControl x:Name="SpinnerControl"
Width="55"
Height="55"
Grid.RowSpan="2" />
<TextBlock x:Name="TxtNoResultsMessage"
FontSize="{StaticResource PhoneFontSizeLarge}"
Text="No results found"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Grid.RowSpan="2"
Visibility="Collapsed" />
</Grid>
You could use a ScrollViewer:
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="800"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<ListBox Grid.Row="0">
</ListBox>
<Button Grid.Row="1" Height="30" Content="Test"></Button>
</Grid>
</ScrollViewer>
Simply divide the Grid inside into two rows, the second one being for the Button.
For your specific case it would be:
<Grid x:Name="ContentGrid"
Grid.Row="2">
<ScrollViewer>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="600"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<ListBox x:Name="LBoxItems"
HorizontalAlignment="Left"
Margin="24, 0"
SelectionChanged="LBoxItems_SelectionChanged" Grid.Row="0">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="{StaticResource PhoneTouchTargetOverhang}" >
<TextBlock FontSize="{StaticResource PhoneFontSizeMediumLarge}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" Foreground="{StaticResource PhoneAccentBrush}"
Text="{Binding Title.Text}" TextWrapping="Wrap" Margin="-4,20,0,0">
</TextBlock>
<TextBlock Text="{Binding PublishDate, Converter={StaticResource ItemPublishDateConverter}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Content="Sample" Height="30" Grid.Row="1" />
</Grid>
</ScrollViewer>
</Grid>
Of course, you can set the appropriate height depending on your situation.
What you want to do, really is to mix and match different items in the DataTemplate. If you're not really happy with how the other solutions work out I might consider adding a button to the datatemplate, but set its visibility to collapsed. Then for the very last entry, set its visibility to visible.
Either way you are in for a bit of a hack, but this way the button is in your list box. If all the button events point to the same handler, and only one is visible, you should be good to go.
I had the same problem and tried using the ScrollViewer approach, however I couldn't get rid of the 'stuck scrolling' issue until I disabled the vertical scrollbar on the listbox. Maybe this will help others too.

Resources