Fill up DataGrid with empty rows - wpf

I have a DataGrid bound to a DataTable. I want the DataGrid to always have at least ten (empty) rows, also if there are not enough real data-items (the data comes in little by little).
One approach would be to easily add ten empty rows to the DataTable at initialization. But when a real data-item comes in, I can't easily add the row, I have to find the first empty row to overwrite it, what is not very handy.
So someone knows a smarter/built-in way to achieve this?

It's gonna be mess, no matter from what side it's approached. I'd say your best bet (provided that your grid cells content won't be wrapped) is to use a visual brush (with lines) as your DataGrid's background.
UPDATE 1 - XAML
It's alwast there, the trick is to use MinHeight, which will produce a vision of blank items thanks to tiled background. If your grid will be populated with the real data the background will expand, rendering more lines.
One thing I didn't try is how it'll handling scrolling.
Here's an example:
<Grid>
<Grid.Resources>
<VisualBrush x:Key="StripesBrush" TileMode="Tile" Viewport="0,0,5,20"
Viewbox="0,0,10,10" ViewportUnits="Absolute"
ViewboxUnits="Absolute">
<VisualBrush.Visual>
<Line X1="0" X2="10000" Y1="0" Y2="0" Stroke="DarkGray"/>
</VisualBrush.Visual>
</VisualBrush>
</Grid.Resources>
<DataGrid x:Name="g" AutoGenerateColumns="False"
GridLinesVisibility="None"
MinHeight="100"
Height="100"
VerticalAlignment="Top"
Background="{StaticResource StripesBrush}">
<DataGrid.Columns>
<DataGridTextColumn Header="A" Width="Auto" Binding="{Binding Item1}">
<DataGridTextColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="Transparent"></Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="B" Width="Auto" Binding="{Binding Item2}" />
</DataGrid.Columns>
</DataGrid>
</Grid>

if its just for layout, you can simply add a second datagrid with 10 empty rows under your real datagrid. or you take the aproach Dmitry posted and use visual brush

Related

Why in my WPF view is the Content text of my Label control not visible?

I have the following markup:
<StackPanel Grid.Row="0" Orientation="Horizontal">
<StackPanel Orientation="Horizontal" Visibility="{Binding OrgListVisibility}">
<Label Content="Org:" />
<ComboBox ItemsSource="{Binding OrgSelectList, NotifyOnSourceUpdated=True}" SelectedValuePath="Key" DisplayMemberPath="Value" SelectedItem="{Binding OrgId}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Visibility="{Binding BranchListVisibility}">
<TextBlock Text="Branch:" Style="{StaticResource FormLabel}" />
<ComboBox x:Name="BranchList" ItemsSource="{Binding BranchSelectList}" SelectedValuePath="Key" DisplayMemberPath="Value" SelectedItem="{Binding BranchId}" />
</StackPanel>
</StackPanel>
Yet when I run the app, only the text from the TextBlock is visible, and not that of the Label. The latter is in the Visual Tree, with a TextBlock deep down, but that is as far as I can see.
AS REQUESTED: Here is the style for FormLabel:
<Style TargetType="TextBlock" x:Key="FormLabel">
<Setter Property="Height" Value="20" />
<Setter Property="Margin" Value="10" />
<Setter Property="TextAlignment" Value="Right" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>
A SIMILAR PROBLEM:
I found an almost similar problem with a combobox when I bound it to a collection of instances of a generic class. The items' text simply did not show, but they were present in the comboboxes. Selecting on the one by knowing the position of my sought item correctly cascaded to the 2nd combobox, which had visible items, and I could see the correct but invisible item had been selected.
As soon as I change the item source to a list of non-generic objects, the items in the dropdown were visible again.
The code looks fine and as you have mentioned in the comments section that it takes layout space then it may very well happen that the color of your label and the background color of the containing layout be same.
To troubleshoot this, try giving some different background and foreground colors e.g. red or blue to the Label. Hope this helps
Ctrl+Q -> Live Visual Tree
Then hit the "pick element" button and select your label. Check the following properties:
Visibility
Opacity
Content
Also check the child elements of the Label. Setting the Content should result in a tree like this:
If a default style has changed the control template, you might not see the TextBlock as a child here. Also drill into the TextBlock and make sure it has the right Text property, then make sure it and all its parents have the right Opacity and Visibility . Also make sure that the inner TextBlock has space allocated to it by selecting it and turning on the highlighting feature in the live visual tree window.
Can you try this code to see if it works?
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"
Orientation="Horizontal" Visibility="{Binding OrgListVisibility}">
<Label Content="Org:" />
<ComboBox ItemsSource="{Binding OrgSelectList, NotifyOnSourceUpdated=True}"
SelectedValuePath="Key"
DisplayMemberPath="Value"
SelectedItem="{Binding OrgId}" />
</StackPanel>
<StackPanel Grid.Column="1"
Orientation="Horizontal" Visibility="{Binding BranchListVisibility}">
<TextBlock Text="Branch:" Style="{StaticResource FormLabel}" />
<ComboBox x:Name="BranchList"
ItemsSource="{Binding BranchSelectList}"
SelectedValuePath="Key"
DisplayMemberPath="Value"
SelectedItem="{Binding BranchId}" />
</StackPanel>
</Grid>
The Label would take up layout space while not being visible when its Visibility == Hidden. You should check and make sure that your application does not define a global style (one with no Key) for TargetType="Label" where this value could be set:
<Style TargetType="Label"> !!!note that this has no 'Key' associated
[...]
<Setter Property="Visibility" Value="Hidden" />
[...]
</Style>
This would not need to be in the same xaml file in order to be automatically applied, you should check the global dictionary or any other ResourceDictionary linked in the file.
I had the same problem. It turned out that the label Height was too small. Increased the height and its content became visible.

How do I get this DataGridTextColumn's width to take up 100% of the remaining space?

I'm having an issue forcing the width of a text column to take up 100% of its remaining space. The DataGrid itself is nested within a ListView, which is further nested in a ListView. It's data binding is an observablelist of obvservablelists, filled with strings of varying lengths.
I'm building in VS 2012, WPF 4.5, with the MVVM-Light toolkit to help with coupling, etc.
The column I'd like to take up 100% of remaining space is the second column (PropertyValue). I've tried a few different things including:
Setting the Width attribute to "*". This produced a column that was approximately 10 pixels wide.
Setting the Width attribute to "Auto". This produced a column that was, as expected, the minimum required length of the longest string.
Setting the Width attribute to the ActualWidth binding of the parent list. (See the code below) This seems to produce the same result as "Auto". Curiously, I bound the text of this column to the same value, and it was showing 300-1000+ depending on what size I made the window itself. The number did not reflect the width of the column, though.
Setting the Width attribute to a hard value. This was the only time the width of the column was larger than the Auto property, but I would rather not force a particular width.
I tried stripping out everything that I thought was not relevant (including styles and all other elements, and I still end up with the same column widths.
Code is below:
<UserControl x:Class="Foo.Views.XXLViews.XXLInformationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ignore="http://www.ignore.com"
mc:Ignorable="d ignore"
DataContext="{Binding XXLInformationViewModel, Source={StaticResource Locator}}">
<Grid>
<Grid Margin="25,10,0,0" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Orientation="Vertical" Grid.Column="0">
<ListView ItemsSource="{Binding UnknownPropertiesCollections}" BorderThickness="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Padding="-4,2,0,0" Name="ListOfProperties">
<ListView.ItemTemplate>
<DataTemplate>
<ListView ItemsSource="{Binding}" BorderThickness="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" Padding="-8,2,0,0">
<TextBlock Text="{Binding Name}" Style="{StaticResource PropertyListHeader}"/>
<DataGrid ItemsSource="{Binding PropertyCollection}" AutoGenerateColumns="False" Width="Auto">
<DataGrid.Columns>
<DataGridTextColumn Width="Auto" Binding="{Binding Path=PropertyName}" FontWeight="Bold">
</DataGridTextColumn>
<DataGridTextColumn Width="{Binding Path=ActualWidth, ElementName=ListOfProperties}" Binding="{Binding Path=PropertyValue}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</ListView>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
</Grid>
A screen snip of what I am seeing:
I've spent a bit more time than I expected on this, so hoping that someone can give me a clue as to what the issue is. (And I'll be moving the inline styles for those listviews into a global style once everything is finalized).
I changed HorizontalContentAlignment="Stretch" to HorizontalContentAlignment="Center"
This made the DataGrid only as wide as needed. This was good enough for my situation.

Datagrid scroll bar stops working

When I run the app, the vertical scroll bar works as expected. However, when I add a new line/row, the bar (control that should go up and down on the slider) doesn't slide. With the mouse wheel I can scroll up and down the list of rows, and I can click on the up and down arrows. So the scroll bar works, but not as expected. The control should slide up and down, like it does at first, but after adding that new line, it does not.
I hope that is clear enough, I've searched many issues to find this peculiar behavior, but was unsuccessful. Here is the XAML, in part, as it is now:
<DataGrid x:Name="inventoryDataGrid" AutoGenerateColumns="False"
SelectedValuePath="Id"
EnableRowVirtualization="True"
EnableColumnVirtualization="True"
Style="{DynamicResource DataGridDemoStyle}"
CanUserSortColumns="True"
VerticalAlignment="Top"
ItemsSource="{Binding Source={StaticResource claimInventoryViewSource}}"
RowEditEnding="dgInv_RowEditEnding"
CellEditEnding="dgInv_CellEditEnding"
SelectionChanged="dgInv_SelectionChanged"
IsSynchronizedWithCurrentItem="True" CanUserAddRows="False"
RowHeaderWidth="0"
Sorting="DataGrid_Standard_Sorting" MouseDoubleClick="inventoryDataGrid_DoubleClick"
CanUserDeleteRows="True"
SelectionMode="Single"
HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Visible"
Width="999.5"
CommandManager.PreviewCanExecute="Grid_PreviewCanExecute" Grid.Column="0"
Grid.Row="1"
Margin="0,3,0,0" RowDetailsVisibilityMode="VisibleWhenSelected" Height="227"
LostFocus="inventoryDataGrid_LostFocus" Background="#FFFCF2E7"
AlternatingRowBackground="#FFF2F2D6" RowBackground="#FF6FC4BF"
GotFocus="inventoryDataGrid_GotFocus">
<DataGrid.Resources>
<Style x:Key="DataGridCellStyle" TargetType="{x:Type DataGridCell}" >
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="White"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
Thanks!
I was able to solve this issue. The problem was that there was code I implemented a long time ago, in an EndEdit routine (found here: EndEdit equivalent in WPF), which somehow caused this erratic behavior in my datagrid scrollbar.
Once I removed this code, my scrollbar worked without problems. Then of course I had to research a way to save the data in text boxes without the use of EndEdit, but that is way off topic for this Question.

DataGrid column header text wrapping in silverlight

I am using a DataGrid in my silverlight project and I want one column to wrap it's header text. I know using a style for the header might be the answer but I want to know if there is a wrap property for a datagrid column header?
Here is my code:
<data:DataGrid x:Name="gridViewResources"
AutoGenerateColumns="False"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding OpportunityResourceDetailList, Mode=TwoWay}" IsReadOnly="True">
<data:DataGrid.Columns>
<data:DataGridTemplateColumn Header="#" Width="Auto">
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding PositionLevel.FullPositionAndLevelName}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
</data:DataGridTemplateColumn>
Thanks!
I haven't found a way to get Silverlight to automatically wrap the header (in much the same way as the TextWrapping property of a TextBlock does). I suspect that it's not possible due to a limitation of the DataGridColumn.Header property:
Use discretion when using objects as header content; not all Silverlight objects are suitable for use within the limited presentation surface that appears for headers.
However, you can 'manually' wrap header text. If you put a newline in the header text, the header text will be broken over two lines at that point. (In XAML, you use the character entity
.) For example, the following header text appears split over three lines:
<sdk:DataGridTextColumn Header="ABCD
EFGH
IJKL" />
There is no specific property on a DataGridColumn to support this but once you have created the right style it is just as easy - simply set the HeaderStyle property for the specific column.
Create a Style resource with a TargetType of DataGridColumnHeader and set the ContentTemplate property to be a DataTemplate containing a TextBlock with the TextWrapping property set to Wrap. I've enclosed the TextBlock within a Grid panel to keep this closer to the default DataTemplate used by the ContentPresenter. Apply this style to a specific column using the HeaderStyle property or to the whole DataGrid using the ColumnHeaderStyle property.
Note that you will need to constrain the width of the Column to something less than the header text for the wrapping to take affect unless you specifically restrict the width of the TextBlock in the DataTemplate.
<Style x:Key="CustomDataGridColumnHeaderStyle" TargetType="sdk:DataGridColumnHeader" BasedOn="{StaticResource DefaultDataGridColumnHeaderStyle}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding}" TextWrapping="Wrap" />
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
...
<sdk:DataGrid >
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Header="Header Name" Binding="{Binding Xxx}" Width="80" HeaderStyle="{StaticResource CustomDataGridColumnHeaderStyle}"/>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
here is my code
<DataGrid.ColumnHeaderStyle>
<Style TargetType="ContentControl">
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
<Setter Property="ContentTemplate" >
<Setter.Value >
<DataTemplate>
<TextBlock Text="{Binding}" TextWrapping="Wrap" FontWeight="Bold" TextAlignment="Center" LineHeight="20"></TextBlock></DataTemplate>
</Setter.Value>
</Setter>
</Style>
`enter code here`</DataGrid.ColumnHeaderStyle>

WPF - How to have certain ListView items span columns?

I have a set of data that I'd like to present via a WPF ListView in this way:
Column1 Column2 Column3
--GroupName1--
Item1 part2 part3
Item2 part2 part3
--GroupName2--
Item3 part2 part3
Item4 long_text_in_both_columns
Item5 part2 part3
--GroupName1--
Item6 part2 part3
Item7 long_text_in_both_columns
--GroupName3--
Item8 part2 part3
I am starting by working with this basic sample: http://msdn.microsoft.com/en-us/library/ms771309(VS.90).aspx
Item4 and Item7 above have long text that I would like to span the remaining columns (ignoring what the original column headings were for). How can I do this?
I already have some XAML setup with a DataTrigger to replace the default GridViewRowPresenter with a custom TextBlock, but this isn't quite what I'm looking for. I need the data in column 1 to be displayed normally and the width of the first column recognized.
Here's how I ended up solving this with a proper ListView:
<ListView.ItemContainerStyle >
<Style TargetType="ListViewItem">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowAcrossColumns}" Value="True">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding ElementName=myListView, Path=View.Columns[0].Width}" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Padding="6,3,6,3" Text="{Binding Column1Text}" />
<TextBlock Grid.Column="1" Padding="6,3,6,3" Text="{Binding ColumnSpanningText}" />
</Grid>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid>
<GridViewRowPresenter />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
The key is that the DataTriggered Template does not use GridViewRowPresenter, and instead fakes the use of it with its own grid. Some of the padding/margins had to be guessed at to sort of match what GridViewRowPresenter uses internally. The other tricky part was binding the internal Grid columns to the overall ListView column widths. Resizing columns then works as expected.
I think for this, you use ListBox instead of ListView and use its ItemTemplate to split each columns.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Text1}"/>
<TextBlock Text="{Binding Text2}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this way you will have chance to put Trigger in or based on some data, you could make one control invisible and show the long text.
:)
I have a similar problem, where I want some lines to have a multi-column-spanning item that starts in the 5th (of nine) columns. I implemented a variation on #PeteVasi's answer, with two main changes:
You want to bind to ActualWidth rather than Width, or it doesn't work right when e.g. columns are auto-sized.
You can use RelativeSource to avoid specifying myListView by name (which makes it more suitable for use in a style resource).
To do this, change the Width assignment in the ColumnDefinition entries from this:
Width="{Binding ElementName=myListView, Path=View.Columns[0].Width}"
to this:
Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListView}}, Path=View.Columns[0].ActualWidth}"
Further, you don't need to use a nested <Grid>, and if you want to keep the mouse-over and selection highlighting effects, you need to clone the default style.
I experimented with a minor variation on the answer that uses GridViewRowPresenter, and played with a bad idea (watching for column resize events and using them to set a property to which a column width was bound). The various experiments, including a fully-styled version, can be found in the DisasmUiTest project on github.

Resources