I am currently trying to write a small calendar program in C# WPF.
For the datagrid I have written a userControl.
This works like I want it to work. I will still need to update the optics but for now it is good.
The problem is the code of the DataGridTextColums.. It is all redundant.
So if I want to change something I need to change it everywhere.
<DataGrid x:Name="datagrid"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserResizeColumns="False"
CanUserReorderColumns="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
AutoGenerateColumns="False"
SelectionUnit="Cell"
SelectionMode="Extended"
HeadersVisibility="Column"
Background="Transparent"
BorderBrush="Transparent"
ItemsSource="{Binding DataGridSource.DataGridList, RelativeSource={RelativeSource AncestorType=UserControl}}">
<DataGrid.Columns>
<DataGridTextColumn Header="CW" Width="*" IsReadOnly="True" Binding="{Binding CwCell.Text}">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="{Binding CwCell.BackColor}"/>
<Setter Property="BorderBrush" Value="{Binding CwCell.BorderColor}"/>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="OrangeRed"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTemplateColumn Header="MO" Width="*" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Text="{Binding MondayCell.Text}" Margin="5,0,0,0" Width="18"/>
<ItemsControl ItemsSource="{Binding Path=MondayCell.Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" MaxHeight="20"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="4" Height="4" Margin="0,1,1,1" Fill="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="{Binding MondayCell.BackColor}"/>
<Setter Property="BorderBrush" Value="{Binding MondayCell.BorderColor}"/>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip BorderThickness="0" Background="Transparent">
<Grid>
<Border Background="White" BorderBrush="Black" BorderThickness="1">
<StackPanel Orientation="Vertical" DataContext="{Binding MondayCell}">
<TextBlock Text="{Binding AppointmentName}"
Background="White" Width="auto" Margin="5,5,5,1"
TextWrapping="Wrap"
FontWeight="Bold"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<TextBlock Text="{Binding AppointmentDescr}"
Background="White" Margin="5,1,5,5"
TextWrapping="Wrap"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<ItemsControl ItemsSource="{Binding Path=Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="4" Height="4" Fill="{Binding Color}" Margin="5,0,5,0"/>
<Border BorderBrush="Silver" BorderThickness="1,0,0,0" Margin="0,0,0,0"/>
<TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</Grid>
</ToolTip>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="OrangeRed"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="DI" Width="*" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border>
<StackPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Text="{Binding TuesdayCell.Text}" Margin="5,0,0,0" Width="18"/>
<ItemsControl ItemsSource="{Binding Path=TuesdayCell.Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" MaxHeight="20"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="4" Height="4" Margin="0,1,1,1" Fill="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background" Value="{Binding TuesdayCell.BackColor}"/>
<Setter Property="BorderBrush" Value="{Binding TuesdayCell.BorderColor}"/>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip BorderThickness="0" Background="Transparent">
<Grid>
<Border Background="White" BorderBrush="Black" BorderThickness="1">
<StackPanel Orientation="Vertical" DataContext="{Binding TuesdayCell}">
<TextBlock Text="{Binding AppointmentName}"
Background="White" Width="auto" Margin="5,5,5,1"
TextWrapping="Wrap"
FontWeight="Bold"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<TextBlock Text="{Binding AppointmentDescr}"
Background="White" Margin="5,1,5,5"
TextWrapping="Wrap"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<ItemsControl ItemsSource="{Binding Path=Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="4" Height="4" Fill="{Binding Color}" Margin="5,0,5,0"/>
<Border BorderBrush="Silver" BorderThickness="1,0,0,0" Margin="0,0,0,0"/>
<TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</Grid>
</ToolTip>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="OrangeRed"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
<!--same for wednesdayCell to sundayCell-->
</DataGrid.Columns>
</DataGrid>
So as you can see each DataGridTemplateColumn binds to a different Cell (Monday to Sunday).
I tried to create a template out of this. If i keep "MondayCell" in the template (like in the Code below), it works. But obviously I cannot use any other source of data except "MondayCell" then.
See:
<UserControl.Resources>
<DataTemplate x:Key="MyCellTemplate">
<Border>
<StackPanel Orientation="Horizontal" Background="Transparent">
<TextBlock Text="{Binding MondayCell.Text}" Margin="5,0,0,0" Width="18"/>
<ItemsControl ItemsSource="{Binding Path=MondayCell.Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" MaxHeight="20"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Width="4" Height="4" Margin="0,1,1,1" Fill="{Binding Color}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</DataTemplate>
<Style TargetType="{x:Type DataGridCell}" x:Key="MyCellStyle">
<Setter Property="Background" Value="{Binding MondayCell.BackColor}"/>
<Setter Property="BorderBrush" Value="{Binding MondayCell.BorderColor}"/>
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip BorderThickness="0" Background="Transparent">
<Grid>
<Border Background="White" BorderBrush="Black" BorderThickness="1">
<StackPanel Orientation="Vertical" DataContext="{Binding MondayCell}">
<TextBlock Text="{Binding AppointmentName}"
Background="White" Width="auto" Margin="5,5,5,1"
TextWrapping="Wrap"
FontWeight="Bold"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<TextBlock Text="{Binding AppointmentDescr}"
Background="White" Margin="5,1,5,5"
TextWrapping="Wrap"/>
<Border BorderBrush="Silver" BorderThickness="0,1,0,0" Margin="0,1,0,0" />
<ItemsControl ItemsSource="{Binding Path=Addons}" Margin="0,0,7,0">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical">
</StackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Width="4" Height="4" Fill="{Binding Color}" Margin="5,0,5,0"/>
<Border BorderBrush="Silver" BorderThickness="1,0,0,0" Margin="0,0,0,0"/>
<TextBlock Text="{Binding Name}" Margin="5,0,0,0"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</Grid>
</ToolTip>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="OrangeRed"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
Usage in the Datagrid: This works, but only shows the data from MondayCell.
<DataGridTemplateColumn Header="MO" Width="*" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<StaticResource ResourceKey="MyCellTemplate"/>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<StaticResource ResourceKey="MyCellStyle"/>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
How I want to use it, but doesn't work like this:
Any help is appreciated.
For now I keep it redundant, but I would rather use a template so I only need to change 1 piece of code instead of 7.
Thank you for your help!
I would like to present a solution that is based on using a UserControl:
<DataGridTemplateColumn >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:StandardColumn Column="{Binding MondayCell}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local:StandardColumn Column="{Binding TuesdayCell}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The StandardColumn implementation , for simplicity , can be as following:
<UserControl x:Class="Problem8.StandardColumn"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Problem8"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Name="Parent">
<StackPanel>
<TextBlock Text="{Binding ElementName=Parent,Path=Column}"/>
</StackPanel>
</UserControl>
In this userControl we have a dependency property called Column :
public partial class StandardColumn : UserControl
{
public StandardColumn()
{
InitializeComponent();
}
public static readonly DependencyProperty ColumnProperty =
DependencyProperty.Register("Column", typeof(object), typeof(StandardColumn));
public object Column
{
get { return (object)GetValue(ColumnProperty); }
set { SetValue(ColumnProperty, value); }
}
}
We can also make it even more simple by using the DataContext instead of the Column dependency property.
You could build your columns dynamically using a base string out a txt file and use xamlreader.Parse or persist to disk and then use xamlreader.load.
I answered a similar question a while back but I cannot find the answer.
Create a template as a txt file with placeholders for the parts you want to substitute. Here is the example I use in a sample I wrote:
<?xml version="1.0" encoding="utf-8" ?>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="xxMMMxx" TextAlignment="Center" Grid.ColumnSpan="2"/>
<TextBlock Text="Units" Margin="2,0,2,0" Grid.Row="1"/>
<TextBlock Text="Value" Margin="2,0,2,0" Grid.Row="1" Grid.Column="2" />
</Grid>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MonthTotals[xxNumxx].Products}" Margin="2,0,2,0" TextAlignment="Right"/>
<TextBlock Text="{Binding MonthTotals[xxNumxx].Total}" Margin="2,0,2,0" TextAlignment="Right" Grid.Column="1"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Make that content, copy if newer and you will get a txt file next to your exe you can read in.
In this I have a dynamic datagrid as another txt file as well, but that is not totally necessary.
Here's my code builds and adds columns.
You could just work with the txt file as a string and do string substitution. This shows manipulating it as xml which has the potential for you to insert xelements etc. It is setting attributes whilst you can maybe forget that part and just do the string substitution, xamlreader.parse into a datagrid column and add to the columns collection.
It is substituting month numbers in the binding for a range of months.
If you consider a rolling last n month financial report, this is the general idea. Last month would be 3 now in april. 4 when you run in may.
private void Button_Click(object sender, RoutedEventArgs e)
{
// Get the datagrid shell
XElement xdg = GetXElement(#"pack://application:,,,/dg.txt");
XElement cols = xdg.Descendants().First(); // Column list
// Get the column template
XElement col = GetXElement(#"pack://application:,,,/col.txt");
DateTime mnth = DateTime.Now.AddMonths(-6);
for (int i = 0; i < 6; i++)
{
DateTime dat = mnth.AddMonths(i);
XElement el = new XElement(col);
// Month in mmm format in header
var mnthEl = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value.ToString() == "xxMMMxx");
mnthEl.SetAttributeValue("Text", dat.ToString("MMM"));
string monthNo = dat.AddMonths(-1).Month.ToString();
// Month as index for the product
var prodEl = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value == "{Binding MonthTotals[xxNumxx].Products}");
prodEl.SetAttributeValue("Text",
"{Binding MonthTotals[" + monthNo + "].Products}");
// Month as index for the total
var prodTot = el.Descendants("TextBlock")
.Single(x => x.Attribute("Text").Value == "{Binding MonthTotals[xxNumxx].Total}");
prodTot.SetAttributeValue("Text",
"{Binding MonthTotals[" + monthNo + "].Total}");
cols.Add(el);
}
string dgString = xdg.ToString();
ParserContext context = new ParserContext();
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
DataGrid dg = (DataGrid)XamlReader.Parse(dgString, context);
Root.Children.Add(dg);
}
private XElement GetXElement(string uri)
{
XDocument xmlDoc = new XDocument();
var xmltxt = Application.GetContentStream(new Uri(uri));
string elfull = new StreamReader(xmltxt.Stream).ReadToEnd();
xmlDoc = XDocument.Parse(elfull);
return xmlDoc.Root;
}
}
You could potentially build out your entire year view using this sort of approach. Build it as xml or a string. Save to disk. xamlreader.load() it back in as controls off disk.
A similar string manipulation based approach would be to build your control as text. Save as a datatemplate in a resource dictionary. You can load such an uncompiled resource dictionary off disk then and just build once a year. You could build centrally in a small utility app intended just for the purpose and distribute to clients.
This is my second solution. I believe that the selection of the DataGrid as a base have created this complexity. Alternatively we can consider more basic controls.
I am drafting the solution:
The MonthView user control may look as following:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<local:HeaderView Grid.Row="0"/>
<ItemsControl ItemsSource="{Binding Weeks}" Grid.Row="1" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:WeekView/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
The WeekView user control may look as following:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<local:DayView DataContext="{Binding CwCell}" Grid.Column="0"/>
<local:DayView DataContext="{Binding MondayCell}" Grid.Column="1"/>
<local:DayView DataContext="{Binding TuesdayCell}" Grid.Column="2"/>
<local:DayView DataContext="{Binding WednesdayCell}" Grid.Column="3"/>
<local:DayView DataContext="{Binding ThursdayCell}" Grid.Column="4"/>
<local:DayView DataContext="{Binding FridayCell}" Grid.Column="5"/>
<local:DayView DataContext="{Binding FridayCell}" Grid.Column="6"/>
<local:DayView DataContext="{Binding SaturdayCell}" Grid.Column="7"/>
<local:DayView DataContext="{Binding SundayCell}" Grid.Column="8"/>
</Grid>
The DayView user control may look as following:
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding Text}" Width="20" Height="20" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
The HeaderView user control may look as following:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<local:ColumnHeaderView DataContext="CW" Grid.Column="0" />
<local:ColumnHeaderView DataContext="MO" Grid.Column="1" />
<local:ColumnHeaderView DataContext="TU" Grid.Column="2" />
<local:ColumnHeaderView DataContext="WE" Grid.Column="3" />
<local:ColumnHeaderView DataContext="TH" Grid.Column="4" />
<local:ColumnHeaderView DataContext="FR" Grid.Column="5" />
<local:ColumnHeaderView DataContext="SA" Grid.Column="6" />
<local:ColumnHeaderView DataContext="SU" Grid.Column="7" />
</Grid>
The ColumnHeaderView user control may look as following:
<Border BorderBrush="Black" BorderThickness="1">
<TextBlock Text="{Binding }" Width="20" Height="15" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Border>
I want to sort Labels from an ItemsControl to my Grid.
When I bind the Grid.Row and Grid.Column properties, the position of the column and row is not effected.
What am I doing wrong?
Labels have the wrong positions in the grid
Here my View.xaml
<Window.Resources>
<vm:MainViewModel x:Key="MainVM"/>
</Window.Resources>
<DockPanel DataContext="{StaticResource MainVM}">
<Grid Width="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ItemsControl
ItemsSource="{Binding MachineList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" Background="Gainsboro" BorderThickness="1" Margin="2">
<Label Content="{Binding SerialNumber}"
Grid.Column="{Binding StationNumber}"
Grid.Row="{Binding LineNumber}"
Margin="0"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Background="LightBlue"
/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DockPanel>
Here my MainViewModel.cs
public class MainViewModel: BaseViewModel
{
public ObservableCollection<Machine> MachineList { get; set; }
public MainViewModel()
{
Machine m1 = new Machine(0, "Row1 Column3", 1, 3, MachineType.SX);
Machine m2 = new Machine(0, "Row1 Column2", 1, 2, MachineType.SX);
Machine m3 = new Machine(0, "Row2 Column1", 2, 1, MachineType.SX);
MachineList = new ObservableCollection<Machine>();
MachineList.Add(m1);
MachineList.Add(m2);
MachineList.Add(m3);
}
}
The problem is that the ItemsControl displays the items in its own panel, which is no your grid so the grid property have no effect on the location of the items. The correct way to do this is to define your grid in the ItemsControl.ItemsPanel property like this:
<ItemsControl
ItemsSource="{Binding MachineList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Black" Background="Gainsboro" BorderThickness="1" Margin="2">
<Label Content="{Binding SerialNumber}"
Margin="0"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Background="LightBlue"
/>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Width="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{binding ...}" />
<Setter Property="Grig.Column" Value="{binding ...}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
see here in the The ItemsPanelTemplate property section
I have a Windows Store App with a ListBox which contains Grids of variable height. I can't get these to align at the top. I've tried every combo of VerticalAlignment and VerticalContentAlignment I can think of, and they're always centered vertically.
Here's my XAML
<Page
x:Class="MyApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid Margin="50,50,50,50" HorizontalAlignment="Stretch" Width="Auto">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="80"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="" Margin="12,0,0,0" Style="{StaticResource HeaderTextStyle}" />
<Grid Grid.Row="1" Margin="30,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300"></ColumnDefinition>
<ColumnDefinition Width="15"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="15"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" x:Name="bxAddItem" Width="300" Height="28" Margin="0,0,0,0" Text="Item text" KeyUp="bxAddItem_KeyUp" GotFocus="bxAddItem_GotFocus" LostFocus="bxAddItem_LostFocus"></TextBox>
<ComboBox Grid.Column="2" x:Name="comboList" SelectionChanged="comboList_SelectionChanged" Width="100" Height="32">
<ComboBoxItem Tag="0">No List</ComboBoxItem>
</ComboBox>
<Button Grid.Column="4" x:Name="btnAddItem" Click="AddItem_Click" HorizontalAlignment="Left" Background="#45000000" Height="34">Add an Item</Button>
</Grid>
<ScrollViewer HorizontalScrollBarVisibility="Visible" Grid.Row="2">
<ListBox Width="Auto" VerticalContentAlignment="Top" ItemsSource="{Binding ToDoLists}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Beige">
<Grid.RowDefinitions>
<RowDefinition Height="50"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="{Binding Title}"></TextBlock>
<ListBox Grid.Row="1" Grid.Column="0" Name="ToDoList" ItemsSource="{Binding Path=Items}"
Margin="24,0,0,0" Height="Auto" MinWidth="200" VerticalAlignment="Stretch"
BorderBrush="BlueViolet" SelectionChanged="ToDoList_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding ItemName}"></TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel VerticalAlignment="Top" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListBox>
</ScrollViewer>
</Grid>
</Grid>
</Page>
EDIT:
Sheridan's answer does not work for me. There may be something else on the page that's causing the issue.
I've updated the question to include the entire page code.
EDIT 2:
This post was incorrectly tagged as WPF when in fact the issue is in a Windows Store app. This code works perfectly in WPF, hence the confusion. However it does NOT work in a Windows Store app
Have you tried setting the ItemContainerStyle to VerticalAlignment="Top"
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="VerticalAlignment" Value="Top"></Setter>
</Style>
</ListBox.ItemContainerStyle>