When setting the Width of a data grids colum to * the columns will appear somehow collapsed like in the screenshot below.
After I add some data to the data grid and somehow force a redraw, the columns suddenly appear as expected. What am I doing wrong here?
I'm using DataGridTemplateColumn. Below is some sample code:
<DataGridTemplateColumn Width="*"
Header="Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Content="{Binding FullName, ValidatesOnNotifyDataErrors=True}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding FullName, ValidatesOnNotifyDataErrors=True, TargetNullValue={x:Static sys:String.Empty}, Mode=TwoWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
I found the issue: I added an empty group style and that causes the columns to appear like shown in the screenshot above.
Related
※ Add Info
I forgot to tell one thing is each list item have to get their own color (refer image)
Click Here!
I already tried to using stackpanel, but it coudln't display the color for each items.
I'm trying to find the way split the specific row in wpf.
Image
The following attachment is the format what i want to make by wpf.
To merge Row is not what I want.(becacuse I want to split the row data in one instance)
The data(1~3-3) is member property of each Instance.
Does anybody can solve this problem?
I'll look forward to you guys answer.
thank you
You can use a DataGrid instead like this:
<DataGrid Name="dg" Width="400" Height="300" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Id}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridTemplateColumn Header="Addresses">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Address1}" />
<TextBlock Text="{Binding Address2}"/>
<TextBlock Text="{Binding Address3}"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Please change the bindings of the columns with your data context properties.
I have a datagrid in XAML with 4 separate columns, all with * for their width. All seems fine in Visual Studio with the control, everything looks good in the design view.
When I run my program however, all my columns shrink down to just 5 or so pixels of width, and nothing, not even clicking and dragging on the borders of the columns to resize them will change their width. Occasionally when I run my program I even see the columns start at their normal width, and then shrink down to their minimum size one pixel at a time over several seconds.
Upon some investigation, it seems that the issue is somehow related to using * as the Width of the columns, as if I change all the columns to Auto or a fixed width everything works fine in that column for some reason.
Below is the XAML code I'm having trouble with.
<GroupBox Header="header text" Margin="4"
Visibility="{Binding BindTarget, Converter={StaticResource BooleanToVisibilityConverter}}">
<DataGrid Margin="4" ItemsSource="{Binding}" DataContext="{Binding DataContextTarget}"
AutoGenerateColumns="False" MaxHeight="250" CanUserDeleteRows="False"
EnableRowVirtualization="False" CanUserSortColumns="True" CanUserResizeColumns="True">
<DataGrid.Columns>
<DataGridTemplateColumn Width="0.8*">
<DataGridTemplateColumn.Header>
<TextBlock Text="ResourceHeader1" TextWrapping="Wrap" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox
IsChecked="{Binding IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="True" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" IsReadOnly="True">
<DataGridTemplateColumn.Header>
<TextBlock Text="Name" TextWrapping="Wrap" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FieldName1}" IsEnabled="True" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" IsReadOnly="True">
<DataGridTemplateColumn.Header>
<TextBlock Text="Model" TextWrapping="Wrap" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FieldName2}" IsEnabled="True" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="*" IsReadOnly="True">
<DataGridTemplateColumn.Header>
<TextBlock Text="Manufacturer" TextWrapping="Wrap" />
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FieldName3}" IsEnabled="True" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</GroupBox>
As you can see in the XAML, I even enabled letting users manually resize the column width in the datagrid, but that doesn't make a difference, the columns still refuse to be resized if I set their width to *.
Any ideas what's causing this bizarre issue?
The datagrid is not in a panel, so when it measures itself, it will take up the smallest amount of space it can while still drawing its children. Since your columns desire *, they each get a proportion of that minimum space. The default desired size for things with width of * is the greater of 0 and MinWidth, so your columns get scrunched to their minimum width. If you put the DataGrid into a Grid or other panel, the DataGrid would fill the panel's space, and each column would get proportional amounts of the DataGrid's space. This would also happen if you set a Width or MinWidth on the DataGrid.
When you set the column widths to auto, they will take up the space they need, and when the datagrid measures itself, it will include all of the columns' desired sizes as part of its own desired size. The datagrid will grow to accommodate the columns.
After doing some more searching on StackOverflow I've found a solution to my issue, though I still have no clue what caused my issue in the first place.
Nested Scroll Areas
See Daniel's answer in the above linked thread, wrapping my Datagrid in his RestrictDesiredSize class and giving it a minimum height and width like below fixes my issue.
<local:RestrictDesiredSize MinHeight="50" MinWidth="200">
<!-- Datagrid XAML goes here -->
</local:RestrictDesiredSize>
I am trying to get a WPF DataGrid to sort by a column by default and it isn't working. there is no sorting happening. The sort icons appear and if i click them then sorting happens.
Right now my table has just the one column. but is it still not sorting it by default.
Any ideas what i am missing?
<DataGrid.Columns>
<!--Ordinal-->
<DataGridTemplateColumn d:DataContext="{d:DesignInstance tabViewModels:ColumnViewModel}"
SortMemberPath="Ordinal"
>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<Label Content="#" ToolTip="Column Position" />
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<xctk:DoubleUpDown Value="{Binding Ordinal, UpdateSourceTrigger=PropertyChanged, TargetNullValue=''}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Ordinal}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
One solution would be to use a LINQ query to give the data already sorted to the DataGrid. Modify the getter of the Item Source with something like this:
List<Something> MyItemSource
{
get
{
return _myItemSource.OrderBy(x => x.Ordinal).ToList();
}
}
then it will for sure sort by Ordinal.
Currently i bind to a List<T> so i have to do specific set foreach Column a separate DataTemplate
like this:
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock TextAlignment="Center"
Text="{Binding ObColl[1].Std, UpdateSourceTrigger=PropertyChanged}"
Background="{Binding ObColl[1].DienstColor, TargetNullValue=Transparent,FallbackValue=Transparent}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
but i want is to create the DataTemplate one time as Resources
<DataGrid.Resources>
<DataTemplate x:Name="MyCellTemplate">
<TextBlock TextAlignment="Center"
Text="{Binding Std, UpdateSourceTrigger=PropertyChanged}"
Background="{Binding DienstColor, TargetNullValue=Transparent,FallbackValue=Transparent}" />
</DataTemplate>
</DataGrid.Resources>
and use it like
<DataGridTemplateColumn CellTemplate="{StaticResource MyCellTemplate} ??{Binding ObColl[1]}??"/>
But to do so i need to specific the DataContext (ObColl[Idx]) in my DataGridTemplateColumn
but how do i do this?
EDIT
the xaml should look like :
<DataGrid Name="dataGrid1"
ItemsSource="{Binding Itemlist, UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Resources>
<DataTemplate x:Key="MyCellTemplate">
<TextBlock TextAlignment="Center"
Text="{Binding Std, UpdateSourceTrigger=PropertyChanged}"
Background="{Binding DienstColor, TargetNullValue=Transparent, FallbackValue=Transparent}" />
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<!-- Column 1 -->
<DataGridTemplateColumn CellTemplate="{StaticResource MyCellTemplate}"
DataContext={Binding ObColl[0]}/>
<!-- Column Header 2 -->
<DataGridTemplateColumn CellTemplate="{StaticResource MyCellTemplate}"
DataContext={Binding ObColl[1]}/>
</DataGrid.Columns>
</DataGrid>
the DataContext={Binding ObColl[1]} is the problem part because it doesn't exist ....
Ok, here is my understanding of you requirement... you have a MyRow class with two properties; MyRowheader and MyCellList. You want to display the MyRowheader value and one value from the MyCellList collection on each row of your DataGrid. This is how I would do that:
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding YourCollection}">
<DataGrid.Columns>
<DataGridTextColumn Header="Header" Binding="{Binding MyRowheader,
UpdateSourceTrigger=PropertyChanged}" />
<DataGridTemplateColumn Header="Cell list">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding MyCellList[1].Std, UpdateSourceTrigger=
PropertyChanged}" Background="{Binding MyCellListl[1].DienstColor, TargetNullValue=
Transparent, FallbackValue=Transparent}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Please let me know if I have misunderstood your requirement.
UPDATE >>>
So I did misunderstand your requirement. It seem as though you want one value from your MyCellList collection in each column, not row, of the DataGrid. In that case, my answer would be no, you can't setup your DataGrid.Columns using a DataTemplate or any other XAML saving feature. XAML is a verbose language... there are a few ways of writing it more efficiently, but not many. You will often find repeated code on XAML pages.
The only way that I can think of that you could write less code would be if you dynamically generated the columns from code. You can find a basic example of that in the Dynamically add Columns to DataGrid in wpf post. I don't know how much time that will save you though really.
I have several instances where I would like to have several controls in a single column in a datagrid.
For example, I have a dataset that contains images with matching description, image source, timestamp, geotag, etc. I would like to display this information with a thumbnail image in one column and the majority of data in either a textbox or a label. Other datasets I have require textbox / checkbox, or textbox / combobox.
When I attempt to add a second control I receive an error reporting that The property "VisualTree" is set more than once.
<DataGridTemplateColumn Header="Data" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label Name="Description" Content="{Binding Desc}"></Label>
<Label Name="Camera" Content="{Binding Camera}"></Label>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
The DataTemplate should have only one element, I believe - so you should use a Panel to contain the elements, say something like this:
<DataGridTemplateColumn Header="Data" Width="100">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Name="Description" Content="{Binding Desc}"></Label>
<Label Name="Camera" Content="{Binding Camera}"></Label>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
You could of course use WrapPanel, Grid, or anything else you like - StackPanel just appears to be what you're going for.