Adding a counter to a DataTemplate - xaml

I have a DataTemplate for an ItemsControl that outputs a Grid with some binded controls, and this works as expected.
However, I want the first column of the Grid to output a counter of each Grid made.
For example...
<DataTemplate x:Key="myDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<TextBlock Text="X" /> <!-- I want a counter to go here -->
<TextBox Grid.Column="1" Text="{Binding Path=Name}" />
</Grid>
</DataTemplate>
I want that first TextBlock to display 1, 2, 3, 4, etc... as the DataTemplate outputs new Grids.
Any ideas on the best way to do that?
Thanks!

You can achieve this using AlternationCount and AlternationIndex of ItemsControl. Like,
<ItemsControl ItemsSource="{Binding Items}" AlternationCount="{Binding Items.Count}">
<ItemsControl.ItemTemplate>
<DataTemplate x:Key="myDataTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75" />
<ColumnDefinition Width="150" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource TemplatedParent}}" />
<TextBox Grid.Column="1" Text="{Binding Path=Name}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This will give you 0 based index; you can use IValueConverter if any changes needed.

Related

Define listview in resource file with only ItemSource changing

I created the following ListView to display some data (removed extraneous markup):
<ListView ItemsSource="{Binding NewYorkResidents}">
<ListView.Header>
<Style>
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListView.Header>
<ListView.HeaderTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name" Grid.Column="0" />
<TextBlock Text="Address" Grid.Column="1" />
</Grid>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Grid.Column="0" />
<TextBlock Text="{Binding Address}" Grid.Column="1" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Now I want to reuse this exact same ListView + markup in a different view, just with a different ItemsSource (though it will bind to the same data type).
What is the best way to reuse the ListView and just specifiy the ItemsSource? I'm hoping to be able to do something like this:
<ListView DataTemplate="MyTemplate" ItemsSource=<some new binding> />
and still have it show the ListView headers and Name and Address TextBlocks using data from the ItemsSource.
Making a ControlTemplate doesn't seem like the right thing because I am specifiying actual data in the list view also (such as binding to name and address).
Is there a better way to create some type of resource so I can reuse this?
Define the header template and item template in resource dictionary and add reference of them in your code. you can reuse this templates.
<DataTemplate x:Key="HeaderTemplate1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Name" Grid.Column="0" />
<TextBlock Text="Address" Grid.Column="1" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="ListViewTemplate1">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Name}" Grid.Column="0" />
<TextBlock Text="{Binding clothing1}" Grid.Column="1" />
</Grid>
</DataTemplate>
<ListView HeaderTemplate="{StaticResource HeaderTemplate1}" ItemTemplate="{StaticResource ListViewTemplate1}"/>
for more information on Item template:
https://learn.microsoft.com/en-us/windows/uwp/controls-and-patterns/listview-item-templates

XAML Columndefinitions width * not taking available space

I know how the columndefinition works in XAML but there is something I want to do and don't know how.
I want 4 columns like that:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
column has fixed width
column must take all the available space (yes it is between columns and this is exactly the problem)
column has fixed width
column has fixed width
The 2nd column contains text and the problem is that when that text is too short the 2nd column does not take all the available space. it get's smaller automatically and this for each row. I can make it work with this code in the textblock:
MinWidth="2000"
But it's not the good way since this number could be too low when the screen is big.
Here the whole listview containing the 4 columns:
<ListView Grid.Row="1" Grid.ColumnSpan="4" ItemsSource="{Binding blabla}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Image Height="110" Width="110" Grid.Column="0" Source="{Binding blabla}" HorizontalAlignment="Stretch" />
<TextBlock Text="{Binding blabla}" TextWrapping="Wrap" Margin="5,0,0,0" Grid.Column="1" FontSize="16" HorizontalAlignment="Stretch" TextAlignment="Left" FlowDirection="LeftToRight" MinWidth="2000" VerticalAlignment="Center" ScrollViewer.HorizontalScrollBarVisibility="Disabled" FontStretch="UltraCondensed"/>
<TextBlock Grid.Column="2" TextWrapping="Wrap" Foreground="Black" Margin="5,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
<Image Source="{Binding blabla, Converter={StaticResource ImgConverter}}" Grid.Column="3" Width="76" Height="76" HorizontalAlignment="Center" Stretch="None" VerticalAlignment="Center" Margin="0"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Your layout is well-defined but missed a small thing that is causing that the content of the Listviewitem is margined to the left because that is defined in the default ListViewItemStyle which is named "ItemContainerStyle" for the ListView Control .
All what you need to do is add this ListViewItemStyle that I've modified to stretch the content Horizontally and Vertically across all the available space for the item to your Resources
<Style x:Key="StretchedListViewItemStyle"
TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment"
Value="Stretch" />
<Setter Property="VerticalContentAlignment"
Value="Stretch" />
</Style>
Then set it as the ItemContainerStyle for the ListView as follows:
<ListView Grid.Row="1" Grid.ColumnSpan="4" ItemsSource="{Binding blabla}" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" ItemContainerStyle="{StaticResource StretchedListViewItemStyle}"/>

How to align images to the right and text to the left?

I'm trying to set my layout to appear as follows:
Using the following XAML:
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Name="txtSiteName" VerticalAlignment="Top" Width="auto"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Grid.Column="1" HorizontalAlignment="Right">
<tabs:TabItem Name="tabSettings" TabItemText="Settings"
TabItemImage="settings.png" Margin="5" />
<tabs:TabItem Name="tabDelete" TabItemText="Delete Site"
TabItemImage="delete.png" Margin="5" />
</StackPanel>
</Grid>
However, it's appearing as:
What do I need to do to get the images to align to the right, and have the text vertically aligned on the left?
Try This
<Grid >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Name="txtSiteName" VerticalAlignment="Top" Width="auto"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Grid.Column="2" HorizontalAlignment="Right">
<tabs:TabItem Name="tabSettings" TabItemText="Settings"
TabItemImage="settings.png" Margin="5" />
<tabs:TabItem Name="tabDelete" TabItemText="Delete Site"
TabItemImage="delete.png" Margin="5" />
</StackPanel>
</Grid>
A parent container isn't stretching to fill the available space.
You can try
<Grid HorizontalAlignment="Stretch" >
<!-- etc -->
and, if that doesn't work, move up the tree until you find the element that's not stretching.
OP Edit in support of the correct answer:
It turns out this is correct - A parent container wasn't stretching to fill the space.
The parent container was the ListBox that I was inserting the items into.
Where before I had just this:
<ListBox Name="SiteListBox" Grid.Row="2" />
I changed it to the following to force the containing ListBoxItems to stretch:
<ListBox Name="SiteListBox" Grid.Row="2">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch"></Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Change the TextBlock's Vertical Alignment to Center.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="txtSiteName" VerticalAlignment="Center"/>
<StackPanel Orientation="Horizontal" VerticalAlignment="Top" Grid.Column="1" HorizontalAlignment="Right">
<tabs:TabItem Name="tabSettings" TabItemText="Settings"
TabItemImage="settings.png" Margin="5" />
<tabs:TabItem Name="tabDelete" TabItemText="Delete Site"
TabItemImage="delete.png" Margin="5" />
</StackPanel>
</Grid>
And try switching your column definitions.

Grid column definitions

Inside the same StackPanel I'd like to put a control aligned on the left and another one on the right side. I made an attempt using a Grid and defining ColumnDefinitions but with no luck.
<StackPanel Orientation="Horizontal">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="72" />
</Grid.ColumnDefinitions>
<StackPanel HorizontalAlignment="Left" Grid.Column="0" Orientation="Horizontal">
<Button />
</StackPanel>
<StackPanel HorizontalAlignment="Right" Grid.Column="1">
<Button Height="72" Width="72" />
</StackPanel>
</Grid>
</StackPanel>
The first column usually will take from 50% to 80% of the total width (depending on the content), while the second column will always take 72px. How can I set the first column so that it fills the total Grid width minus 72px?
Set the Width property of the first column to Star:
<ColumnDefinition Width="*" />
Making the change in your code should work:
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="72" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal">
<Button />
</StackPanel>
<StackPanel HorizontalAlignment="Right" Grid.Column="1">
<Button Height="72" Width="72" />
</StackPanel>
</Grid>
</StackPanel>

WinRT hardcoded ListViewItem vs. DataTemplate, why do they not look/work the same?

I'm new to WinRT so apologies if this is a silly question. I've created the following ListView:
<ListView x:Name="MyListView1"
Grid.Row="1"
Margin="120,300,0,0"
Width="500"
HorizontalAlignment="Left">
<ListViewItem Background="DodgerBlue">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<TextBlock Text="hardcoded value 1" Grid.Column="0"></TextBlock>
<TextBlock Text="hardcoded value 2" Grid.Column="1"></TextBlock>
</Grid>
</ListViewItem>
</ListView>
This looks the way I want it to look, and if you click an item it will select the whole row. However, if I move this into a DataTemplate it doesn't look the same, and you can no longer click the whole row. (If I add an ItemContainerStyle with the target type ListViewItem and set the background to yellow, it will fill it up so it's the same size as the hardcoded ListItem, but you can only click the yellow outline to select it.) This is the code:
<ListView x:Name="MyListView2"
ItemTemplate="{StaticResource MyTemplate}"
ItemsSource="{Binding MyData}"
Grid.Row="1"
Margin="120,0,0,0"
Width="500"
HorizontalAlignment="Left">
</ListView>
And in StandardStyles.xaml:
<DataTemplate x:Key="MyTemplate">
<ListViewItem Background="DodgerBlue">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MyDataOne}" Grid.Column="0"></TextBlock>
<TextBlock Text="{Binding MyDataTwo}" Grid.Column="1"></TextBlock>
</Grid>
</ListViewItem>
</DataTemplate>
I don't understand why they don't look/work the same - shouldn't it get populated with the exact same code when you bind it? What do I need to do to make it work?
The problem there is the way you created the datatemplate. Remember that ListViewItem is a wrapper added to any object that needs to be displayed in the list, so when you create a datatemplate that contains a listviewitem you are basically wrapping the object twice. All you need to do is remove the listviewitem element from the datatemplate
<DataTemplate x:Key="MyTemplate">
<Grid Background="DodgerBlue">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding MyDataOne}" Grid.Column="0"></TextBlock>
<TextBlock Text="{Binding MyDataTwo}" Grid.Column="1"></TextBlock>
</Grid></DataTemplate>