Вы находитесь на странице: 1из 13

Grid Panel

Introduction How to define rows and columns How to add controls to the grid Resize columns or rows How to share the width of a column over multiple grids Using GridLenghts from code

Introduction

The grid is a layout panel that arranges its child controls in a tabular structure of rows and columns. Its functionality is similar to the HTML table but more flexible. A cell can contain multiple controls, they can span over multiple cells and even overlap themselves. The resize behaviour of the controls is defined by the HorizontalAlignment and VerticalAlignment properties who define the anchors. The distance between the anchor and the grid line is specified by the margin of the control

Define Rows and Columns


The grid has one row and column by default. To create additional rows and columns, you have to add RowDefinitionitems to the RowDefinitions collection and ColumnDefinition items to the ColumnDefinitions collection. The following example shows a grid with three rows and two columns. The size can be specified as an absolute amount of logical units, as a percentage value or automatically. Fixed Auto Fixed size of logical units (1/96 inch) Takes as much space as needed by the contained control are like percentages, except that the sum of all star columns does not have to be 100%. Remember that star-sizing does not work if the grid size is calculated based on its content. <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />

Star (*) Takes as much space as available, percentally divided over all star-sized columns. Star-sizes

<RowDefinition Height="*" /> <RowDefinition Height="28" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="200" /> </Grid.ColumnDefinitions> </Grid>

How to add controls to the grid


To add controls to the grid layout panel just put the declaration between the opening and closing tags of the Grid. Keep in mind that the row- and columndefinitions must precced any definition of child controls. The grid layout panel provides the two attached properties Grid.Column and Grid.Row to define the location of the control. <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> <RowDefinition Height="28" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="200" /> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="Name:"/> <Label Grid.Row="1" Grid.Column="0" Content="E-Mail:"/> <Label Grid.Row="2" Grid.Column="0" Content="Comment:"/> <TextBox Grid.Column="1" Grid.Row="0" Margin="3" /> <TextBox Grid.Column="1" Grid.Row="1" Margin="3" /> <TextBox Grid.Column="1" Grid.Row="2" Margin="3" /> <Button Grid.Column="1" Grid.Row="3" HorizontalAlignment="Right" MinWidth="80" Margin="3" Content="Send" /> </Grid>

Resizable columns or rows

WPF provides a control called the GridSplitter. This control is added like any other control to a cell of the grid. The special thing is that is grabs itself the nearest gridline to change its width or height when you drag this control around. <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Label Content="Left" Grid.Column="0" /> <GridSplitter HorizontalAlignment="Right" VerticalAlignment="Stretch" Grid.Column="1" ResizeBehavior="PreviousAndNext" Width="5" Background="#FFBCBCBC"/> <Label Content="Right" Grid.Column="2" /> </Grid>

The best way to align a grid splitter is to place it in its own auto-sized column. Doing it this way prevents overlapping to adjacent cells. To ensure that the grid splitter changes the size of the previous and next cell you have to set theResizeBehavior to PreviousAndNext. The splitter normally recognizes the resize direction according to the ratio between its height and width. But if you like you can also manually set the ResizeDirection to Columns or Rows. <GridSplitter ResizeDirection="Columns"/>

How to share the width of a column over multiple grids


The shared size feature of the grid layout allows it to synchronize the width of columns over multiple grids. The feature is very useful if you want to realize a multi-column listview by using a grid as layout panel within the data template. Because each item contains its own grid, the columns will not have the same width. By setting the attached property Grid.IsSharedSizeScope to true on a parent element you define a scope within the column-widths are shared. To synchronize the width of two columndefinitions, set the SharedSizeGroup to the same name. <ItemsControl Grid.IsSharedSizeScope="True" > <ItemsControl.ItemTemplate> <DataTemplate> <Grid>

<Grid.ColumnDefinitions> <ColumnDefinition SharedSizeGroup="FirstColumn" Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Text="{Binding Path=Key}" TextWrapping="Wrap"/> <TextBlock Text="{Binding Path=Value}" Grid.Column="1" TextWrapping="Wrap"/> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>

Useful Hints
Columns and rows that participate in size-sharing do not respect Star sizing. In the size-sharing scenario, Star sizing is treated as Auto. Since TextWrapping on TextBlocks within an SharedSize column does not work you can exclude your last column from the shared size. This often helps to resolve the problem.

Using GridLenghts from code


If you want to add columns or rows by code, you can use the GridLength class to define the differenz types of sizes.

Auto sized Star sized Fixed size

GridLength.Auto new GridLength(1,GridUnitType.Star) new GridLength(100,GridUnitType.Pixel)

Grid grid = new Grid(); ColumnDefinition col1 = new ColumnDefinition(); col1.Width = GridLength.Auto; ColumnDefinition col2 = new ColumnDefinition(); col2.Width = new GridLength(1,GridUnitType.Star); grid.ColumnDefinitions.Add(col1); grid.ColumnDefinitions.Add(col2);

WPF DataGrid Control

Introduction
Since .NET 4.0, Microsoft is shipping a DataGrid control that provides all the basic functionality needed, like: Auto generation of columns Manual definition of columns Selection Grouping Column sorting, reordering and resizing Row Details Alternating BackgroundBrush Frozen columns Headers Visibility How to template autogenerated columns

Basic usage: Auto generate columns


To show a basic data grid , just drop a DataGrid control to your view and bind the ItemsSource to a collection of data objects and you're done. The DataGrid provides a feature called AutoGenerateColumns that automatically generates column according to the public properties of your data objects. It generates the following types of columns: TextBox columns for string values CheckBox columns for boolean values ComboBox columns for enumerable values Hyperlink columns for Uri values

<DataGrid ItemsSource="{Binding Customers}" />

Manually define columns

Alternatively you can define your columns manually by setting the AutoGenerateColumns property to False. In this case you have to define the columns in the Columns collection of the data grid. You have the following types of columns available: DataGridCheckBoxColumn for boolean values DataGridComboBoxColumn for enumerable values DataGridHyperlinkColumn for Uri values DataGridTemplateColumn to show any types of data by defining your own cell template DataGridTextColumn to show text values

<DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False" > <DataGrid.Columns> <DataGridTemplateColumn Header="Image" Width="SizeToCells" IsReadOnly="True"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Image Source="{Binding Image}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid>

Selection
The data grid includes a variety of selection modes. They are configured by the SelectionMode and SelectionUnit property. The SelectionMode can be set to Single or Extended to define if one or multiple units can be selected simultaneously. The SelectionUnit defines the scope of one selection unit. It can be set to Cell, CellAndRowHeader and FullRow.

<DataGrid ItemsSource="{Binding Customers}" SelectionMode="Extended" SelectionUnit="Cell" />

Column sorting, reordering and resizing


The data grid provides features to sort, reorder and resize columns. They can be enabled or disabled by the following properties: CanUserReorderColumns enables or disables column re-ordering CanUserResizeColumns enables or disables column resizing CanUserResizeRows enables or disables row resizing CanUserSortColumns enables or disables column sorting

<DataGrid ItemsSource="{Binding Customers}" CanUserReorderColumns="True" CanUserResizeColumns="True" CanUserResizeRows="False" CanUserSortColumns="True"/>

Grouping
The data grid also supports grouping. To enable grouping you have to define a CollectionView that contains to least oneGroupDescription that defines the criterias how to group.

Customers = new ListCollectionView(_customers); Customers.GroupDescriptions.Add(new PropertyGroupDescription("Gender"));

Second thing you need to do is defining a template how the groups should look like. You can do this by setting the GroupStyle to something like the following snippet.

<DataGrid ItemsSource="{Binding GroupedCustomers}"> <DataGrid.GroupStyle> <GroupStyle> <GroupStyle.HeaderTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Path=Name}" /> </StackPanel> </DataTemplate> </GroupStyle.HeaderTemplate> <GroupStyle.ContainerStyle> <Style TargetType="{x:Type GroupItem}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type GroupItem}"> <Expander> <Expander.Header> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Path=Name}" /> <TextBlock Text="{Binding Path=ItemCount}"/> <TextBlock Text="Items"/> </StackPanel> </Expander.Header> <ItemsPresenter /> </Expander> </ControlTemplate> </Setter.Value> </Setter> </Style> </GroupStyle.ContainerStyle> </GroupStyle> </DataGrid.GroupStyle> </DataGrid>

Row Details
The data grid provides a feature that shows a detail panel for a selected row. It can be enabled by setting a DataTemplate to theRowDetailsTemplate property. The data template gets the object that is bound to this row passed by the DataContext and can bind to it.

<DataGrid ItemsSource="{Binding Customers}"> <DataGrid.Columns> <DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" /> </DataGrid.Columns> <DataGrid.RowDetailsTemplate> <DataTemplate> <Image Height="100" Source="{Binding Image}" /> </DataTemplate> </DataGrid.RowDetailsTemplate> </DataGrid>

Row Details depending on the type of data


You can specify a RowDetailsTemplateSelector that selects a data template according to the type or data that this row contains. To do this, create a type that derives from DataTemplateSelector and override the SelectTemplate method. In the items argument you get the data and you can determine which data template to display. Return an instance of that data template as return value.

public class GenderTemplateSelector : DataTemplateSelector { public DataTemplate MaleTemplate { get; set; } public DataTemplate FemaleTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { var customer = item as Customer; if (customer == null) return base.SelectTemplate(item, container); if( customer.Gender == Gender.Male) { return MaleTemplate; } return FemaleTemplate; } }

<l:GenderTemplateSelector x:Key="genderTemplateSelector"> <l:GenderTemplateSelector.MaleTemplate> <DataTemplate> <Grid Background="LightBlue"> <Image Source="{Binding Image}" Width="50" /> </Grid> </DataTemplate> </l:GenderTemplateSelector.MaleTemplate> <l:GenderTemplateSelector.FemaleTemplate> <DataTemplate> <Grid Background="Salmon"> <Image Source="{Binding Image}" Width="50" /> </Grid> </DataTemplate> </l:GenderTemplateSelector.FemaleTemplate> </l:GenderTemplateSelector> <DataGrid ItemsSource="{Binding Customers}" RowDetailsTemplateSelector="{StaticResource genderTemplateSelector}" />

Alternating BackgroundBrush
You can define a an AlternatingRowBackground that is applied every even row. You can additionally specify an AlternationCount if you only want to ink every every n-th data row.

<DataGrid ItemsSource="{Binding Customers}" AlternatingRowBackground="Gainsboro"

AlternationCount="2"/>

Frozen Columns
The data grid also supports the feature to freeze columns. That means they stay visible while you scoll horizontally through all columns. This is a useful feature to keep a referencing column like an ID or a name always visible to keep your orientation while scrolling.

To freeze a numer of columns just set the FrozenColumnCount property to the number of columns you want to freeze.

<DataGrid ItemsSource="{Binding Customers}" FrozenColumnCount="2"

/>

Headers visbility
You can control the visibility of row and column headers by setting the HeadersVisibility property to either None,Row,Column or All

<DataGrid ItemsSource="{Binding Customers}" HeadersVisibility="None" />

How to template autogenerated columns


If you want to autogenerate columns using AutoGenerateColumns="True", you cannot use CellTemplates, because the DataGridautogenerates either a text, combo, hyperlink or checkbox column, but none of these are templateable. A simple workaround is to hook into the autogeneration, cancel it and always create a DataGridTemplateColumn. The following snippet shows the idea (the code is just a draft): public class MyDataGrid : DataGrid { public DataTemplateSelector CellTemplateSelector { get { return (DataTemplateSelector)GetValue(CellTemplateSelectorProperty); } set { SetValue(CellTemplateSelectorProperty, value); } } public static readonly DependencyProperty CellTemplateSelectorProperty = DependencyProperty.Register("Selector", typeof(DataTemplateSelector), typeof(MyDataGrid), new FrameworkPropertyMetadata(null));

protected override void OnAutoGeneratingColumn(DataGridAutoGeneratingColumnEventArgs e) { e.Cancel = true; Columns.Add(new DataGridTemplateColumn { Header = e.Column.Header, CellTemplateSelector = CellTemplateSelector }); } }

<l:MyDataGrid ItemsSource="{Binding}" AutoGenerateColumns="True" CellTemplateSelector="{StaticResource templateSelector}" />

Designtime vs. Runtime


Introduction
An application often looks great at runtime, but when you open it in a designer like VisualStudio or Expression Blend, the experience is quite different. The rason is that at designtime: UserControls are not embedded in a parent view o Width and Height are not set Root Element is replaced by the designer ViewModel is not created No mouse and keyboard events Design time extensions loaded Constructor of the root-element is not called o o

Controls behave different o o

This can be kind of annoying, especially if you want to edit data templates or layout controls.

Designtime attributes
To improve the design experience, Microsoft provides special designtime attributes that can be added to any WPF element and serve as a hint for the design tool. The designtime attributes are defined in a special namespace, that is usually mapped to the d: prefix. To tell the XAML parser not to interprete these attributes at runtime, the markup compatibility namespace is mapped to mc: and with themc:Ignorable="d" instruction, the d: namespace is excluded. <Window xmlns:d ="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" />

d:DesignHeight

and d:DesignWidth

The d:DesignHeight and d:DesignWidth sets a fixed height and width for the element at designtime <UserControl xmlns="http://schemas.microsoft.com/..." xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" d:DesignWidth="640" d:DesignHeight="480" > <UserControl />

d:LayoutOverrides If a property is set to a fixed value at runtime, but you want to override it at designtime, you can use thed:LayoutOverrides attribute. All properties that should be ignored at designtime can be listed, separated by a semicolon. <Border Height="250" Width="160" d:LayoutOverrides="Width, Height" > </Border>

Вам также может понравиться