Why this example from Pro Silverlight 4 book doesnt work? - silverlight

I am reading a Pro Silverlight 4 book (http://my.safaribooksonline.com/book/programming/csharp/9781430229797/xaml/element-to-element_binding), and I do all examples from the book. But an example from the binding chapter doesnt work for me. The slider doesnt move after I compile and run the application:
<UserControl
x:Class="SilverlightApplication14.MainPage"
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">
<Grid
x:Name="LayoutRoot"
Background="White">
<Slider
x:Name="sliderFontSize"
Margin="3"
Minimum="1"
Maximum="40"
Value="10"></Slider>
<TextBlock
Margin="10"
Text="Simple Text"
x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
</Grid>

Dave S, is absolutely correct. You can see the Z-Index problem reversing the order of the controls (so the TextBlock is before the Slider)- it will then work because the slider will be on top of the TextBlock:
<Grid
x:Name="LayoutRoot"
Background="White">
<TextBlock
Margin="10"
Text="Simple Text"
x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
<Slider
x:Name="sliderFontSize"
Margin="3"
Minimum="1"
Maximum="40"
Value="10"></Slider>
</Grid>
You can see here that Z-Index is determined by the order of controls in the XAML.
An alternate way round this (or to demonstrate) is to specify the Z-Index attached property explicitly:
<Grid
x:Name="LayoutRoot"
Background="White">
<Slider
x:Name="sliderFontSize"
Margin="3"
Minimum="1"
Maximum="40"
Value="10" Canvas.ZIndex="1"></Slider>
<TextBlock
Margin="10"
Text="Simple Text"
x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
</Grid>
The best way to fix this is to simply make sure that the elements don't overlap each other, by putting them in different rows:
<Grid
x:Name="LayoutRoot"
Background="White">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Slider Grid.Row="1"
x:Name="sliderFontSize"
Margin="3"
Minimum="1"
Maximum="40"
Value="10"></Slider>
<TextBlock
Margin="10"
Text="Simple Text"
x:Name="lblSampleText"
FontSize="{Binding ElementName=sliderFontSize, Path=Value}"></TextBlock>
</Grid>
In this sample, the TextBlock is in row 0 and the slider is in row 1, so they no longer overlap.

Both the Slider and the TextBlock are in the Grid in the same position (0,0). This means the TextBlock is being shown drawn directly on top of the Slider so any mouse events will always be captured by the TextBlock and not the Slider. This is implicitly implied as the TextBlock has the higher Z-Index by being defined second in the Grid. If you re-arrange the Grid and apply either Grid.Row="1" or Grid.Column="1" to the TextBlock so it is beside the Slider control you should be able to use the Slider successfully.

Related

Change the height of the title bar

Question: Can we change the height of the title bar displayed in MahApps.Metro?
Details: For instance, in the following XAML example from the MahApps team, I want to display the content Deploy CupCake - of the TextBlock - below the image of the CupCake. So I removed the Orientation="Horizontal" from the StackPanel in the following XAML. As shown in the snapshot below, the content Deploy CupCake is now showing below the image of CupCake - but it is hiding almost all of it. How can we make this content show all of it below the CupCake image?
Snapshot of the Toolbar with MahApps.Metro: Only about 10% of the content is showing below the image.
<mah:MetroWindow x:Class="SampleApp.MainWindow"
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:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
GlowBrush="{DynamicResource MahApps.Brushes.Accent}"
ResizeMode="CanResizeWithGrip"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<mah:MetroWindow.LeftWindowCommands>
<mah:WindowCommands>
<Button Click="LaunchGitHubSite" ToolTip="Open up the GitHub site">
<iconPacks:PackIconModern Width="22"
Height="22"
Kind="SocialGithubOctocat" />
</Button>
</mah:WindowCommands>
</mah:MetroWindow.LeftWindowCommands>
<mah:MetroWindow.RightWindowCommands>
<mah:WindowCommands>
<Button Click="DeployCupCakes" Content="Deploy CupCakes">
<Button.ContentTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<iconPacks:PackIconModern Width="22"
Height="22"
VerticalAlignment="Center"
Kind="FoodCupcake" />
<TextBlock Margin="4 0 0 0"
VerticalAlignment="Center"
Text="{Binding}" />
</StackPanel>
</DataTemplate>
</Button.ContentTemplate>
</Button>
</mah:WindowCommands>
</mah:MetroWindow.RightWindowCommands>
<Grid>
<!-- Your content -->
</Grid>
</mah:MetroWindow>
First of all, it is better to use a to use a panel that distributes the available space among its content, like a Grid, to prevent cutting off content as with the StackPanel. Here, the data template defines a Grid with two rows, where the TextBlock scales to its desired size and the icon takes up the remaining available space. Also note the HorizontalAlignment of the icon, it is centered.
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<iconPacks:PackIconModern Grid.Row="0"
Width="22"
Height="22"
HorizontalAlignment="Center"
Kind="FoodCupcake" />
<TextBlock Grid.Row="1"
Margin="4 0 0 0"
VerticalAlignment="Center"
Text="{Binding}" />
</Grid>
</DataTemplate>
The same result could also be achieved using a DockPanel, where the last child (in this case the icon) takes up the remaining available space, so the order of the defined controls is important.
<DataTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Bottom"
Margin="4 0 0 0"
VerticalAlignment="Center"
Text="{Binding}" />
<iconPacks:PackIconModern DockPanel.Dock="Top"
Width="22"
Height="22"
HorizontalAlignment="Center"
Kind="FoodCupcake" />
</DockPanel>
</DataTemplate>
In both cases you will get the result below, a button with a centered icon and a text below.
To make the button more prominent, change the title bar height with the TitleBarHeight property.
<mah:MetroWindow x:Class="SampleApp.MainWindow"
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:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
GlowBrush="{DynamicResource MahApps.Brushes.Accent}"
ResizeMode="CanResizeWithGrip"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d"
TitleBarHeight="50">

How to make a WPF window resizable if a Grid row contains a collapsed element

I have a problem with the design of a resizable WPF window.
The result shall be that the window elements are resized automatically while changing the width and height of the window by dragging with the mouse.
The base panel is a Dockpanel on which the first element is a ToolBar which is positioned at the top.
Then comes a Grid with two rows.
In each of the rows is a DockPanel with inner elements.
Some of these elements can be hidden by Visibilty.Collapsed (which would be made by properties in the final version).
For testing purposes i have two DockPanels after ToolBar and i have set the visibility of the first in the XAML file to Collapsed.
When i start the application the window seems to be correct.
But as i click the bottom of the window for changing the height by dragging, the second Dockpanel gets smaller and the place where the collapsed Dockpanel would have been gets visible.
What have i done wrong?
Here is my XAML:
<Window x:Class="WPFResizable.MainWindow"
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"
xmlns:local="clr-namespace:WPFResizable"
mc:Ignorable="d"
Title="MainWindow"
SizeToContent="Height"
Width="525">
<DockPanel VerticalAlignment="Stretch" Background="AliceBlue">
<Button DockPanel.Dock="Top" Height="40" Content="ToolBar"/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" Visibility="Collapsed">
<GroupBox Margin="5"
Header="Group 1">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBox Text="Test 1"
MinWidth="400"
MinHeight="100"
Margin="5"/>
</ScrollViewer>
</GroupBox>
</DockPanel>
<DockPanel Grid.Row="1" Grid.Column="0" VerticalAlignment="Stretch">
<GroupBox Margin="5"
Header="Group 2">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBox Text="Test 2"
MinWidth="400"
MinHeight="100"
Margin="5"/>
</ScrollViewer>
</GroupBox>
</DockPanel>
</Grid>
</DockPanel>
</Window>
I think this will do what you want, if I correctly understand what you're trying to do.
VerticalAlignment="Stretch" is redundant on a Grid child, and if there's only one column, you don't need to specify Grid.Column on the children.
Your first grid row had Height="*", which resulted in it taking up half the height of the grid whether or not its content was visible. I've written a Style with a Trigger that changes that row's height to Auto when its content is not visible. This depends on there being exactly one element in the row, but since you've got a DockPanel there, you seem to be thinking along those lines already.
<Grid DockPanel.Dock="Bottom">
<Grid.RowDefinitions>
<RowDefinition>
<RowDefinition.Style>
<Style TargetType="RowDefinition">
<!--
Must set the default in a Setter instead of an attribute, or
dependency property precedence will override the trigger
below.
-->
<Setter Property="Height" Value="*" />
<Style.Triggers>
<DataTrigger
Binding="{Binding Visibility, ElementName=TopChildPanel}"
Value="Collapsed"
>
<Setter Property="Height" Value="Auto" />
</DataTrigger>
</Style.Triggers>
</Style>
</RowDefinition.Style>
</RowDefinition>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<DockPanel x:Name="TopChildPanel" Grid.Row="0" Visibility="Visible">
<GroupBox Margin="5"
Header="Group 1">
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<TextBox Text="Test 1"
MinWidth="400"
MinHeight="100"
Margin="5"/>
</ScrollViewer>
</GroupBox>
</DockPanel>
<DockPanel Grid.Row="1">
<GroupBox
Margin="5"
Header="Group 2">
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
>
<TextBox
Text="Test 2"
MinWidth="400"
MinHeight="100"
Margin="5"/>
</ScrollViewer>
</GroupBox>
</DockPanel>
</Grid>

xaml layout introduction for Qt programmer

I am used to Qt and its Qt Designer.
XAML with its layout controls 'grid' and 'StackPanel' are somehow similar, but I still miss or do not find some of the most common properties of designs in Qt. Since I am completely new to XAML I would like to know the answers or further available documentations.
For example I want to add 2 elements (lets say buttons) either horizontal or vertical with their default height and a minimum height and minimum width. If aligned horizontal they shall be pushed to the left side and the remaining side on the right should be free. That means that the size of the buttons does not increase if the windows size is increased. In Qt this is realized by a grid in combination with a spacer (see for example this tutorial for an example).
My first XAML is far away from what I expect. The definition of RowDefinition is copied from a tutorial. However I do not understand its meaning...
<Window x:Class="SpectrumViewer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Spectrum Viewer" Height="350" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="8" VerticalAlignment="Top">
<Button MinWidth="75" MaxHeight="23" Margin="10" HorizontalAlignment="Left" Width="100" Name="buttonTest">test</Button>
<TextBox MinWidth="75" MaxHeight="23" Margin="10" HorizontalAlignment="Left" Width="150" Name="textBoxValue"/>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="8" >
<Button MinWidth="75" MaxHeight="23" Margin="10" HorizontalAlignment="Left" Width="100" Name="button1">button 1</Button>
<Button MinWidth="75" MaxHeight="23" Margin="10" HorizontalAlignment="Left" Width="100" Name="button2">button 2</Button>
</StackPanel>
</Grid>
</Window>
The next image shows that the elements are pushed to the left side, but the two stacked panels above each other are not pushed to the top. If I set them both with VerticalAlignment="Top" they overlap which is also wrong.
If I resize the window one can see that the elements are not resized and that the second StackPanel overlaps with the first:
Instead the elements should be resized to the minimum width and any further resizing of the windows should be prohibited.
The first problem of the two stack panels overlapping when you set both VerticalAlignment to Top is because since you haven't specified in which Grid.Row they should be, the default would be both in Grid.Row = 0. Specify the row index and they won't overlap :
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="8" VerticalAlignment="Top">
....
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="8" VerticalAlignment="Top">
....
</StackPanel>
There is no way the window would stop resizing when the minimum size of the buttons is reached. You could set the MinWidth of the Grid and ask the window to stop right there :
<Window x:Class="SpectrumViewer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Spectrum Viewer" Height="350" Width="525"
MinWidth="{Binding RelativeSource={RelativeSource Self}, Path=Content.MinWidth}">
<Grid MinWidth="350">
.......
</Grid>
</Window>
Or set the MinWidth of the Window itself :)

WPF: how to get remaining width in a StackPanel?

Given the code below:
<Window x:Class="Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window3" Height="300" Width="300">
<StackPanel Background="Yellow" Orientation="Horizontal">
<TextBlock Background="Green" Text="some text" Width="200"/>
<TextBox Width="{Binding ???}" />
<TextBlock Background="Red" Text="some text" Width="50"/>
</StackPanel>
</Window>
how do you bind second textbox's width as to fill the remaining space?
Please keep in mind I'm looking for a binding solution: I know how to do it using other layouts (like DockPanel or grid) but I'm not interested in that. Also, using ElementName is not of interest.
Thanks.

Centering a WPF control

I have a window where I add a new UserControl to (with an image), I simply want to center the control in the middle of the screen (both vertically and horizontally). I can only get the vertical one to work. I'm gonna swap content in the DockPanel from my CodeBehind and want to show this startup screen before I start doing my slideshow UI, this means that the content is set from the CodeBehind.
My Window:
<Window x:Class="GreenWebPlayerWPF.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="512" Width="853" WindowStyle="None" WindowState="Maximized" WindowStartupLocation="CenterScreen">
<DockPanel Width="Auto" Height="Auto" Name="TransitionContainer" Background="Black" Margin="0" LastChildFill="True"></DockPanel>
</Window>
My UserControl:
<UserControl x:Class="GreenWebPlayerWPF.FrontPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel Background="Black">
<Image Name="image1" Stretch="None" Source="/GreenWebPlayerWPF;component/gw.png" />
</DockPanel>
</UserControl>
Please note that I'm using maximized/full screen.
Use a Grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Replace with your UserControl -->
<Button Content="Foo" Grid.Column="1" Grid.Row="1"/>
</Grid>
You can dock it inside your DockPanel (if you must have a DockPanel there) to stretch. And, of course, while the above is all markup, you can just as easily create such a grid from code.
I keep running into this problem when trying to center elements on the page.
The problem with the StackPanel is that HorizontalAlignment has no effect when the Orientation is Horizontal and VerticalAlignment no effect when Orientation is Vertical. So you keep banging your head trying to set values with no effect. It is not illogical that it works this way but it would be good if this was reported as an error.
The solution I found is to have two imbricated StackPanels one centered horizontally and the other vertically as shown below. Finding the size of the parent is needed to size the intermediate panel otherwise it would be flat and its content hidden - an absolute value would work as well. Although not a panacea itis a bit less verbose than using a grid.
<StackPanel Background="Bisque" Orientation="Vertical" Width="300" Height="300" >
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"
Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=StackPanel}, Path=ActualHeight}">
<StackPanel VerticalAlignment="Center" Width="200" Height="60" Background="Blue">
</StackPanel>
</StackPanel>
</StackPanel>
It's quite an old one, but centring a control is now as simple as:
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center" Height="350" Width="600">
<TextBox />
</StackPanel>
</Grid>

Resources