Archive

Posts Tagged ‘Grid’

XAML Fu Basics – Panels

May 17th, 2009 No comments

No matter what you do with WPF you’re going to run into panels at some point. Having a good understanding of the available panels and what they do is essential to creating or modifying a UI in WPF. People keep asking for a basic overview of the panels so this is my attempt to shed some light on the situation. Questions? Something you don’t understand? Put it in the comments and I’ll do my best to explain the concept.

Canvas
A Canvas can be used to place UI elements anywhere in an area.A Canvas allows you to precisely position elements within a region. This is also one of the few panels that allows elements to easily overlap (the other I know of is the Grid). In many cases you might think you need to use a Canvas, you don’t. Much like the GOTO a Canvas is a royal pain in the butt to maintain and it tends to break layouts when changing window sizes or adding new elements. The only possible reason I have ever seen for using a canvas is when laying out drawing elements (e.g. Path, Shapes) or when you’re Bea Stollnitz making a cool example.

DockPanel

A DockPanel can be used to dock UI elements to the edges of the area.The DockPanel allows you to dock UI elements to the edge of the panel while letting another element fill the rest of the space. It is a great replacement for most uses of the Grid because of its lighter weight.  The DockPanel is one of my favorite panels for larger scale layouts and should become one of yours as well.

Grid

A Grid allows you to create the standard table layout with the normal table features like column and row span.The Grid is probably the most powerful of all panels. It is also one of the heaviest in terms of CPU and memory usage. That isn’t to say that you should avoid using a Grid if you need one, just don’t use it in every place you need a panel if another type of panel (other than Canvas) will work just as well. With a Grid you can make any layout you could make with HTML tables. You can size columns and rows either based on their content (Row Height/Column Width=”Auto”) or based on what the Grid is contained in (Row Height/Column Width=”*”).

StackPanel

A vertical StackPanel stacks its elements one on top of the other.The StackPanel is the bread and butter of many layouts and especially within control templates. Basically the StackPanel stacks items either vertically or horizontally. One thing to be careful of: the StackPanel is unconstrained in the direction it is stacking, e.g. you could stack buttons right off the screen and even if you add scrollbars depending on the visual tree they may never appear.

UniformGrid

The UniformGrid UI elements in a grid with none of the special Grid features like column or row span, but you don't have to specify the number of columns or rows.The UniformGrid is an interesting control. It lays out elements in as near to a square grid as it can without having to specify the number of rows or columns within it. The most common use I’ve found for this is as the ItemsPanel in an ItemsControl. Say you want all of your items displayed in two equal columns. All you have to do is tell the UniformGrid you want two columns and it will make two equal columns and fill the items into however many rows are required.

WrapPanel

A WrapPanel acts just like a StackPanel except when the UI elements reach a boundry they will start wrapping to the next line.The WrapPanel acts much like a StackPanel except that when the items stack to the edge of the panel they wrap. The same caveats with scroll bars apply, in many cases you have to set a height or width to get it to wrap items properly (since the height and width properties are basically evil try using MaxHeight/Width).

Edit: Here is a similar post on Code Project with some more advanced examples.

How to use a Grid as an ItemsHost

April 8th, 2009 No comments

You know how sometimes you run into problems that you know should be really simple but you just can’t manage to solve them? Well one of those problems for me was making a grid an ItemsHost and actually having it work. Sure you can always set IsItemsHost=”True” but you’ll just end up with every item in your ItemsSource all stacked on top of each other. A few weeks ago I ran into this same problem again and couldn’t find a way around it. So after beating my head against the wall for a few hours I finally gave up and posted on StackOverflow, within a half hour I had the answer I’d been trying to figure out for the better part of a day.

It turns out that setting IsItemsHost to True on a panel creates the required ContentPresenters and nothing you can do will let you get at them directly (believe me, I tried). The solution is to create a keyless style that targets ContentPresenter and let this style take care of the dirty work.

Without furthur ado, here’s an example.

The Data

Class DataPoint
	Private myRow As Integer
	Public Property Row() As Integer
		Get
			Return myRow
		End Get
		Set(ByVal value As Integer)
			myRow = value
		End Set
	End Property

	Private myCol As Integer
	Public Property Col() As Integer
		Get
			Return myCol
		End Get
		Set(ByVal value As Integer)
			myCol = value
		End Set
	End Property

	Private myText As String
	Public ReadOnly Property Text() As String
		Get
			Return myText
		End Get
	End Property

	Public Sub New(ByVal x As Integer, ByVal y As Integer)
		Me.Row = y
		Me.Col = x
		myText = "Column " + x.ToString + ", Row " + y.ToString
	End Sub
End Class

Load the test data and set it as the data context for the window

Class GridAsItemsHostExample
	Private myTestData As TestData

	Public Sub New()
		InitializeComponent()

		myTestData = New TestData()
		Me.DataContext = myTestData
	End Sub
End Class

Class TestData
	Private myDataSet As List(Of DataPoint)
	Public Property DataSet() As List(Of DataPoint)
		Get
			Return myDataSet
		End Get
		Set(ByVal value As List(Of DataPoint))
			myDataSet = value
		End Set
	End Property

	Public Sub New()
		Me.DataSet = New List(Of DataPoint)
		For x As Integer = 0 To 1
			For y As Integer = 0 To 1
				Me.DataSet.Add(New DataPoint(x, y))
			Next
		Next
	End Sub
End Class

And finally the window, note the ContentPresenter style.

<Window x:Class="GridAsItemsHostExample"
		xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
		xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
		Title="Grid As ItemsHost Example"
		SizeToContent="WidthAndHeight">

	<ItemsControl ItemsSource="{Binding DataSet}">
		<ItemsControl.ItemContainerStyle>
			<Style TargetType="ContentPresenter">
				<Setter Property="Grid.Column"	Value="{Binding Col}"	/>
				<Setter Property="Grid.Row"		Value="{Binding Row}"	/>
				<Setter Property="Margin"		Value="5"				/>
			</Style>
		</ItemsControl.ItemContainerStyle>
		<ItemsControl.ItemTemplate>
			<DataTemplate>
				<TextBlock Text="{Binding Text}"   />
			</DataTemplate>
		</ItemsControl.ItemTemplate>
		<ItemsControl.Style>
			<Style TargetType="{x:Type ItemsControl}">
				<Setter Property="Template">
					<Setter.Value>
						<ControlTemplate TargetType="{x:Type ItemsControl}">
							<Grid HorizontalAlignment="Stretch"
								  IsItemsHost="True"
								  ShowGridLines="True">
								<Grid.ColumnDefinitions>
									<ColumnDefinition />
									<ColumnDefinition />
								</Grid.ColumnDefinitions>
								<Grid.RowDefinitions>
									<RowDefinition />
									<RowDefinition />
								</Grid.RowDefinitions>
							</Grid>
						</ControlTemplate>
					</Setter.Value>
				</Setter>
			</Style>
		</ItemsControl.Style>
	</ItemsControl>
</Window>
Categories: Code Samples Tags: , , ,