I have a DataGrid (the official one) with SelectionUnit="Cell". When the user selects a cell, I'd like to show the row details for the corresponding row. This is apparently not the default behavior, and I can't seem to figure out how to accomplish this.
Here's my XAML:
<UserControl x:Class="View.Test"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../AppResources.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Path=Fields}"
BorderBrush="Transparent"
HeadersVisibility="Column"
SelectionMode="Single"
SelectionUnit="Cell"
CanUserAddRows="False"
CanUserDeleteRows="False"
CanUserSortColumns="False"
IsTextSearchEnabled="True"
x:Name="EntryGrid"
>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" Width="Auto" IsReadOnly="True"/>
<DataGridTemplateColumn Header="Value" Width="Auto" x:Name="valueColumn" MinWidth="60" MaxWidth="90">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=DisplayValue}" TextTrimming="CharacterEllipsis" ToolTip="{Binding Path=Text, RelativeSource={RelativeSource Self}}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DockPanel>
<ComboBox TabIndex="1" HorizontalAlignment="Stretch" VerticalAlignment="Center" SelectedValue="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="Value" ItemsSource="{Binding Path=FieldOptions}" Visibility="{Binding Path=FieldOptions, Converter={StaticResource EmptyCollectionIsInvisibleConverter}}" />
<TextBox TabIndex="2" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" HorizontalAlignment="Stretch" Visibility="{Binding Path=FieldOptions, Converter={StaticResource NonEmptyCollectionIsInvisibleConverter}}"/>
</DockPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Description" IsReadOnly="True" Width="*" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Description}" TextWrapping="Wrap" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Help}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</UserControl>
You can set the SelectionUnit to FullRow
SelectionUnit="FullRow"
or you can handle the selection event and set the visibility on event handling.
private void EntryGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
foreach (var cell in e.AddedCells)
((DataGridRow)EntryGrid.ItemContainerGenerator.ContainerFromItem(cell.Item)).DetailsVisibility = System.Windows.Visibility.Visible;
foreach (var cell in e.RemovedCells)
((DataGridRow)EntryGrid.ItemContainerGenerator.ContainerFromItem(cell.Item)).DetailsVisibility = System.Windows.Visibility.Collapsed;
}
Insert disparaging remarks about the WPF DataGrid here.
Related
I ask this question because I can't get it to work.
<UserControl.Resources>
<ObjectDataProvider x:Key="vmObjDataProv" ObjectType="{x:Type vm:SomeViewModel}"/>
</UserControl.Resources>
The thing is that when I use the following xaml it works (the ListBox is filled):
<ListBox ItemsSource="{Binding Source={StaticResource vmObjDataProv}, Path=TestList}" Grid.Row="2" Grid.Column="1"/>
But when I do the following it doesn't work anymore:
<Grid>
<DataGrid Grid.Row="3" Grid.Column="1" DataContext="{StaticResource vmObjDataProv}" ItemsSource="{Binding TestList}" Background="White">
<DataGrid.Columns>
<!--EDITORS-->
<DataGridTemplateColumn Header="Editor" IsReadOnly="True" Width="auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}, Path=Name, Mode=OneWay}" IsReadOnly="True" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
What do I miss?
What you're missing is that the binding mechanism, as in this case:
<ListBox ItemsSource="{Binding Source={StaticResource vmObjDataProv}, Path=TestList}" />
is designed to replace ObjectDataProvider with actual provided data (an instance of SomeViewModel in your case). However, when you have a simple resource reference:
<DataGrid DataContext="{StaticResource vmObjDataProv}" />
the replacement does not happen, thus the actual DataContext is the ObjectDataProvider itself, and not an instance of SomeViewModel. The correct setup would be this:
<DataGrid DataContext="{Binding Source={StaticResource vmObjDataProv}}" />
I got a a few Textblocks and a Datagrid in a grid. The Datagrid vertical scrollbar works fine. But when I put the grid inside a Viewbox the vertical scrollbar disappears. Below is my code
<Window x:Class=MyProject.View.MyTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
WindowStartupLocation="CenterScreen"
Title="{Binding FormTitle}" Height="500" Width="800" >
<Window.InputBindings>
<KeyBinding Key="F7" Command="{Binding PrintCommand}" />
</Window.InputBindings>
<Viewbox VerticalAlignment="Top" HorizontalAlignment="Left" Stretch="UniformToFill" >
<Grid Height="Auto" Width="Auto" Name="rootGrid">
<TextBlock Height="12" HorizontalAlignment="Left" Margin="12,12,0,0" Name="textBlock1" Text="Job ID:" VerticalAlignment="Top" />
<TextBlock Height="12" HorizontalAlignment="Left" Margin="12,28,0,0" Name="textBlock2" Text="Job Run Time:" VerticalAlignment="Top"/>
<TextBlock Height="12" HorizontalAlignment="Left" Margin="12,45,0,0" Name="textBlock3" Text="Run Number:" VerticalAlignment="Top" />
<TextBlock Height="12" HorizontalAlignment="Left" Margin="12,61,0,0" Name="textBlock4" Text="User Name:" VerticalAlignment="Top" />
<DataGrid CanUserAddRows="False" ItemsSource="{Binding ArchInfo}" AutoGenerateColumns="False"
CanUserDeleteRows="False" CanUserReorderColumns="False"
CanUserSortColumns="True" GridLinesVisibility="All"
ColumnHeaderHeight ="40"
Margin="5,124,5,0" IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Table Name" Binding="{Binding Path=TableName, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Table Type" Binding="{Binding Path=TableType, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Status" Binding="{Binding Path=Status, UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Viewbox>
</Window>
If I add the following to the Datagrid the scrollbar will show but it does not function.
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
No matter what I do I can only see part of the Datagrid rows.
Any idea how to resolve this?
Thanks,
The problem has been resolved by Andy's comment.
Setting Datagrid Height and Stretch="Uniform" made it work. See Andy's comment.
is there any simple solution to this problem..first i thought i can create an empty ObservableCollection and writte:
ObservableCollection<PersonDetailsView> newOCollection= new ObservableCollection<PersonDetailsView>();
myDataGrid.ItemsSource=newOCollection.ToArray();
and it works..i get an empty row..but the problem is that i loose the other binding..is there any way to Bind to newOCollection only if my {Binding Person} (see the code) doesn't return a value
<DataGrid CanUserAddRows="True" IsReadOnly="False" BorderBrush="#FFCCCCCC"
GridLinesVisibility="All" AutoGenerateColumns="False"
ItemsSource="{Binding Person}" Background="White" Margin="10,45,0,0"
VerticalAlignment="Top" Height="91" HorizontalAlignment="Left"
HeadersVisibility="None" SelectionMode="Single" Name="dtaPersons" Width="415">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Person.Name, Mode=TwoWay}" Width="Auto"/>
<DataGridTextColumn Binding="{Binding Person.Surname, Mode=TwoWay}" Width="*"/>
<DataGridTemplateColumn Width="Auto">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate >
<Button Style="{DynamicResource ChromelessButtonStyle}" Content="r" FontFamily="Marlett" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
ObservableCollection<PersonDetailsView> newOCollection= new ObservableCollection<PersonDetailsView>();
if (!myDataGrid.Items.Any())
myDataGrid.ItemsSource=newOCollection.ToArray();
I am working on a dataGrid that is populated from an Entity model. I have the following for the specific column as an attempt to use a combobox during editing and the source for the editing is a CollectionsViewSource.
<Grid DataContext="{StaticResource vsLogins}" Grid.Column="1"
Margin="16,248,154,31">
<DataGrid AutoGenerateColumns="False" EnableRowVirtualization="True"
Height="213" HorizontalAlignment="Left"
ItemsSource="{Binding Source={StaticResource vsLogins}}"
Name="LoginsDataGrid"
RowDetailsVisibilityMode="VisibleWhenSelected"
VerticalAlignment="Top" Width="380"
Background="{StaticResource lgb}" BorderThickness="2"
BorderBrush="#FFFC0303">
<DataGrid.Columns>
<DataGridTextColumn x:Name="LoginNameColumn" Binding="{Binding
Path=LoginName}" Header="Login Name"
Width="200" MinWidth="200" />
<DataGridTextColumn x:Name="PsWrdColumn"
Binding="{Binding Path=PsWrd}"
Header="Password" Width="130" MinWidth="130" />
<DataGridTemplateColumn x:Name="AccessLevelIdColumn" Header="Id"
Width="40" MinWidth="40">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=AccessLevelId}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Source={StaticResource
vsAccessLevels}}" DisplayMemberPath="Description"
SelectedValuePath="AccessLevelId" IsEditable="False"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
It is throwing some errors. What am I doing wrong? I also tried putting a grid around the combobox and setting it's dataContent to the CVS - no dice either. Thanks for any help.
<DataGridComboBoxColumn x:Name="AccessIdColumn"
ItemsSource="{Binding Source={StaticResource vsAccessLevels}}"
DisplayMemberPath="Description"
SelectedValuePath="AccessLevelId"
SelectedValueBinding="{Binding Path=AccessLevelId}"/>
I am using the following code :
Where is my mistake? What's the solution?
<MyClass:CheckForVis x:Key="_CheckForVis"/>
</Window.Resources>
<DataGrid Name="dg" AutoGenerateColumns="False"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserSortColumns="False"
ItemsSource="{Binding ElementName=tempWin, Path=TitleClass}" >
<DataGrid.Columns>
<DataGridTemplateColumn Visibility="{Binding ElementName=tempWin, Path=TitleClass,Converter={StaticResource _CheckForVis}}" Width="*" Header="Input" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="10,0,0,0" Grid.Column="0" Name="partMojudi">
<TextBlock Width="Auto" Name="txtInput" Text="{Binding input}"/>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid>
</Grid>
</Window>
Why not right?
Where is my mistake? What's the solution?