Column width issue when displaying table of data in xaml - wpf

I'm attempting to display a table of data which looks like this on Windows Phone 7 (thus I don't have the DataGrid control:
(The columns are: Rank, Score, Win-Loss, Name.)
7 43 22-7 Aaron
2 13 4-7 Beth
5 42 3-1 Clark
And so on. I have used a ListBox with an ItemTemplate to query the values and print them out, with a Grid to format the list. However, each grid entry is separate! I want the columns to all line up, but when an element size is not the same size, it isn't aligned.
This is the code I am using:
<ListBox x:Name="MyListBox" ItemsSource="{Binding AllPlayers}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="10,0,10,0" Text="{Binding Rank}"/>
<TextBlock Grid.Column="1" Margin="10,0,10,0" Text="{Binding Score}"/>
<StackPanel Grid.Column="2" Margin="10,0,10,0" Orientation="Horizontal">
<TextBlock Grid.Column="2" Text="{Binding Wins}"/>
<TextBlock Grid.Column="2" Text="-"/>
<TextBlock Grid.Column="2" Text="{Binding Losses}"/>
</StackPanel>
<TextBlock Grid.Column="3" Margin="10,0,10,0" Text="{Binding Name}"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Is there a better way to do this? I could set the pixel width on the "Grid" column manually, but I'd rather have it auto-figure out the width, if possible.

Since WP7 supports one fixed screen pixel width, you can set exact width for each column. What width to use - that's up to you, depending on the content, but that would be the way to keep them all one size.

Related

How to make changing number of columns fill entire width and center horizontally in WPF?

I have a Grid with 3 Columns in WPF. Each column is filled with a Vertical Stackpanel. The first column (and its content) is always visible. the 2. and 3. column are linked to checkboxes.
And i basically want to have the columns fill the entire horizontal space while also having their content centered (the content of each column is the same) . So for example if only the first column is used, its content should be centered over the whole grid width. If the 2. column is used aswell, The whole grid space should be equaly divided for both columns and their content should be centered inside. With also the third column used, the space would be divided by 3 of course.
My idea for now was the following but i cant get the stackpanels to be centered/fill out the horizontal space.
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" Content="2. Durchgang" IsChecked="{Binding RVPDGsecondround}" Margin ="0,0,0,0"/>
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" Content="3. Durchgang" IsChecked="{Binding RVPDGthirdround}" Margin ="0,0,0,0"/>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="0">
<TextBlock Text="Durchgang 1" Style="{StaticResource MaterialDesignBody2TextBlock}"/>
</StackPanel>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="1" Visibility="{Binding RVPDGsecondround, Converter={StaticResource b2v}}">
<TextBlock Text="Durchgang 2" Style="{StaticResource MaterialDesignBody2TextBlock}"/>
</StackPanel>
<StackPanel Orientation="Vertical" HorizontalAlignment="Center" Grid.Column="2" Visibility="{Binding RVPDGthirdround, Converter={StaticResource b2v}}">
<TextBlock Text="Durchgang 3" Style="{StaticResource MaterialDesignBody2TextBlock}" />
</StackPanel>
</Grid>
A UniformGrid may be better suited than a Grid:
<UniformGrid Rows="1" HorizontalAlignment="Stretch">
<StackPanel HorizontalAlignment="Center">
<TextBlock Text="Column 1"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center" Visibility=...>
<TextBlock Text="Column 2"/>
</StackPanel>
<StackPanel HorizontalAlignment="Center" Visibility=...>
<TextBlock Text="Column 3"/>
</StackPanel>
</UniformGrid>

WPF TreeView ItemTemplate alighments

i have create my own tree-view with multi column Headers using standard wpf controls
Dock Panel
DataGrid , Just for creating the columns and having sorting and resizing capabilities. The height of datagrid is only 25 , we only need to show columns not data here.
The TreeView Control with hierarchy
i have add the image just to understand the problem and the XAML code
The Account Type should be always align at the left no matter how many levels are expanded in the "first column"
somewhere in the xaml of the TreeViewItemTemplate i lost the idea.. Can anyone help me to fix the alignments
<DockPanel DataContext="{StaticResource cust}">
<Button Command="{Binding rld}" Content="reload" DockPanel.Dock="Top"/>
<!--Unbound DataGrid just to display the headers-->
<DataGrid Height="25" DockPanel.Dock="Top" ItemsSource="{Binding Customers}" AutoGenerateColumns="False" Margin="0,0,0,0">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" x:Name="col0"></DataGridTextColumn>
<DataGridTextColumn Binding="{Binding AccountType}" Header="Account Type" x:Name="col1"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
<!--Actual Binding with Tree View and item Template to display the properties-->
<TreeView ItemsSource="{Binding Customers}" DockPanel.Dock="Top">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding rel}">
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ElementName=col0,Path=ActualWidth}"></ColumnDefinition>
<ColumnDefinition Width="{Binding ElementName=col1,Path=ActualWidth}" ></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Name}" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding AccountType}" VerticalAlignment="Center" />
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</DockPanel>
The TreeView naturally indents child items, so its normal what you see.
A possible fix could be to set a negative left margin in the AccountType TextBlock with the same value of the indent, therefore neutralizing the gap.
You need to apply it only if its parent is expanded. This can easily be done modifying a bit your viewmodels.
<TextBlock Grid.Column="1" Margin="{Binding marginPropertyInVM}" Text="{Binding AccountType}" VerticalAlignment="Center"/>
You can limit the size of your first column by changing your template grids column definition to:
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="{Binding ElementName=col1,Path=ActualWidth}" ></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding Name}" VerticalAlignment="Center"/>
<TextBlock Grid.Column="1" Text="{Binding AccountType}" VerticalAlignment="Center" />
</Grid>
This way the first column will only be allowed the remaining width once the 2nd column and indent have been allocated their space.

Creating a Table in XAML and populating it with an Array?

If I have a table like the one below:
<Grid VerticalAlignment="Top" HorizontalAlignment="Left" ShowGridLines="True" Width="250" Height="100">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock FontSize="20" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="0">2005 Products Shipped</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="0">Quarter 1</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="1">Quarter 2</TextBlock>
<TextBlock FontSize="12" FontWeight="Bold" Grid.Row="1" Grid.Column="2">Quarter 3</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0">50000</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="1">100000</TextBlock>
<TextBlock Grid.Row="2" Grid.Column="2">150000</TextBlock>
<TextBlock FontSize="16" FontWeight="Bold" Grid.ColumnSpan="3" Grid.Row="3">Total Units: 300000</TextBlock>
</Grid>
Would I be able to populate it in one go using an array.
For example, if I had an Array containing "Row 1", "Row 2" etc. thru 10 would I be able to populate the first column with those values?
I'm not sure I'm doing a great job of explaining. I know I could do each cell individually, but I want it to cycle through and do all at once?
Thanks
Firstly, consider just using a ListBox or ItemsControl, with a DataTemplate. Define the 2 header rows in a separate grid, and stack this one underneath. The catch with this approach is that you need to define fixed-width columns, since each row will be its own Grid (or actually StackPanel is more performant in this scenario):
<ItemsControl ItemsSource="{Binding TheArray}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Width="100" Text="{Binding Col1}" />
<TextBlock Width="100" Text="{Binding Col2}" />
<TextBlock Width="100" Text="{Binding Col3}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Secondly, if you need to use a true Grid, then one approach could be to define a Behavior on your Grid. This Behavior class would define an Items dependency property. The dependency property's "changed" handler could then create the TextBlocks (x of them for each cell where x is the number of columns), add them to the Grid, and assign the Grid.Row and Grid.Column properties (and even add the RowDefinitions if necessary).
<Grid>
<i:Interaction.Behaviors>
<my:GridItemsBehavior Items="{Binding TheArray}" />
</i:Interaction.Behaviors>
</Grid>
I wouldn't necessarily recommend the latter approach, because you lose a lot of the power of XAML by creating UI in code-behind.

StackPanel expanding outside size of parent grid

I'm pretty new with WPF, so apologies if I'm missing something obvious. I have this template that is bound to items in an obs. collection. I'm trying to get it so that the 2nd column, the "test test..." part has a variable width that fills all the available space in the parent grid.
What I'm finding though, is that my code automatically shows all the text for that "test test..." text box as opposed to just binding to the available space in the grid, and instead creates the scroll bar that you see below.
I instead, want that "test test" to be cut off so that everything else fits so that no scroll bar appears (that when, if the user resizes the screen then that "test test..." textbox will automatically resize to fit the new space). Is there a way to do that?
My code for that template is as follows:
<DataTemplate x:Key="MainTemplate">
<Grid Margin="4" ClipToBounds="True">
<Grid.Resources>
<local:BooleanToHiddenVisibility x:Key="boolToVis"/>
</Grid.Resources>
<StackPanel Orientation="Vertical" ClipToBounds="True">
<Grid Width="Auto" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="60" />
<ColumnDefinition Width="40" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Name="checkViewTextBox"/>
<TextBlock Grid.Column="1" Text="{Binding OriginalQuote}" FontWeight="Bold" TextTrimming="WordEllipsis" FontStyle="Italic" ClipToBounds="True"/>
<TextBlock Margin="10,0,0,0" Grid.Column="2" Text="plane :" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="3" Text="{Binding Mid}" Width="40"/>
<TextBlock Margin="10,0,0,0" Grid.Column="4" Text="data2 :" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="5" Text="{Binding MidTwo}" Width="40"/>
<TextBlock Margin="10,0,0,0" Grid.Column="6" Text="data3:" FontWeight="SemiBold" Width="60"/>
<TextBlock Margin="5,0,0,0" Grid.Column="7" Text="{Binding MidThree}" Width="40"/>
<Button Margin="10,0,0,0" Content="History" Grid.Column="8" Click="History_Click" Width="40"/>
</Grid>
<StackPanel Orientation="Horizontal" Visibility="{Binding Path=IsChecked, ElementName=checkViewTextBox, Converter={StaticResource boolToVis}}">
<StackPanel.Resources>
<Style BasedOn="{StaticResource tbstyle}" TargetType="{x:Type TextBlock}" />
</StackPanel.Resources>
<!--Other stuff thats working ok-->
</StackPanel>
</Grid>
</DataTemplate>
Any help is much appreciated!
P.S. I've been adding random proprieties hoping one will work, so if looks like I have random things on there, that's probably why....
Well, not sure it will help you but some words about WPF layout.
It has two steps: measure and arrange.
At the first stage, the control tries to calculate its desired state. StackPanel asks its children about their desired sizes. It does not limit their size. (TextBlock with the binding to OriginalQoute has no explicitly set width!)
At the second stage, control is arranged.
Stack panel is allowed to occupy the whole left space of the column but it arranges its children as if its size was unlimited, so TextBlock shows the text completely.
The question is how to limit the size of the TextBlock?
Try binding
<TextBlock Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=StackPanel}, Path=ActualWidth}"/>

Textblock.TextTrimming not working inside a grid

I have a 3 column grid for my layout with each of it width set to Width="*". For the middle (2nd) grid, I have another 3 column grid each containing it own textblock, and again the column grids width are set to Width="*".
When the Window is resized, the grids are resized as expected, however the 3rd textblock isn't getting trimmed if the text goes outside the boundary of the grid. I have textbox set with TextTrimming="WordEllipsis" and TextWrapping="Wrap", and the properties are not being enforced for some reason.
Here is some of the code I have:
Layout grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="150" MaxWidth="300" Width="1*" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition MinWidth="150" MaxWidth="500" Width="1*" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
</Grid>
2nd column code:
<Grid Grid.Column="2" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="5" Width="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Path=FeedItems.Count}" Foreground="White" FontSize="18" Width="Auto" FontWeight="SemiBold" />
<TextBlock Text=" items from " Foreground="White" FontSize="18" Width="Auto" Grid.Column="1" />
<TextBlock Text="{Binding Path=Name}" Foreground="White" FontSize="18" Grid.Column="2" TextTrimming="CharacterEllipsis" HorizontalAlignment="Left" Width="Auto" TextWrapping="NoWrap" ClipToBounds="True" />
</Grid>
In order for this to work, you would need the last column in the second grid to have a * size, otherwise it will tell the TextBlock that it has as much space as it wants, even if it doesn't. Auto sized columns won't restrict the content to the bounds of a grid. However, you would probably get better results if you did this with a single TextBlock, and multiple Runs:
<TextBlock FontSize="18" TextTrimming="CharacterEllipsis">
<Run Text="{Binding Path=FeedItems.Count}" FontWeight="SemiBold" />
<Run Text=" items from " />
<Run Text="{Binding Path=Name}" />
</TextBlock>
Note that you can only bind Run.Text as of .NET 4.0. If you're using an older version of the framework, you'll have to create your own BindableRun, which is pretty simple as seen here.

Resources