I have a problem with the default behavior of the resizing of columns:
If a DataGrid is too wide for its container, the horizontal scrollbar appears. If I drag the bar to the right and resize most right column, the scrollbar sticks to the right.
In my case I don't want that behavior. The scrollbar should either just not stick to the right, or, perfect would be, a resize preview like MS Excel.
Can someone tell me how to achieve that?
Edit1: This behavior is fine (not sticking to the right):
If I could realize that easily, I would prefer:
/Edit1
I am using .Net 4.8 for a simple WPF application.
If an example is need, the following will display two grids and the left one can be used for that behavior:
<Window x:Class="DataGridTest.MainWindow"
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:local="clr-namespace:DataGridTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:MasterViewModel/>
</Window.DataContext>
<DockPanel>
<Button DockPanel.Dock="Bottom" Command="{Binding DisplaySelectionCountCommand}">Display Selection Count</Button>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DataGrid Grid.Column="0" ItemsSource="{Binding Items}" AutoGenerateColumns="False"
SelectionMode="Extended" local:MultiSelect.IsEnabled="True" HorizontalScrollBarVisibility="Auto">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" Width="100"/>
</DataGrid.Columns>
</DataGrid>
<DataGrid Grid.Column="1" ItemsSource="{Binding Items}"
SelectionMode="Extended" local:MultiSelect.IsEnabled="True"/>
</Grid>
</DockPanel>
</Window>
CodePudding user response:
When I suggested to listen to the SizeChanged
event I didn't mean the DataGrid
to be the source.
Since you are interested in the columns, you must listen to the cell event of course:
MainWindow.xaml
<DataGrid>
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<EventSetter Event="SizeChanged" Handler="DataGridCell_SizeChanged" />
</Style>
</DataGrid.CellStyle>
</DataGrid>
MainWindow.xaml.cs
private void DataGridCell_SizeChanged(object sender, SizeChangedEventArgs e)
=> (sender as DataGridCell).BringIntoView();
This is an alternative version that shows how to gain more control over the scroll position using the ScrollViewer
of the DataGrid
:
MainWindow.xaml
<DataGrid x:Name="DataGrid"
ScrollViewer.ScrollChanged="DataGrid_ScrollChanged">
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<EventSetter Event="SizeChanged" Handler="DataGridCell_SizeChanged" />
</Style>
</DataGrid.CellStyle>
</DataGrid>
MainWindow.xaml.cs
private double OriginalScrollPosition { get; set; }
private bool IsResizingColumn { get; set; }
private void DataGrid_ScrollChanged(object sender, ScrollChangedEventArgs e)
{
var dataGrid = sender as DataGrid;
if (this.IsResizingColumn
&& TryFindVisualChildElement(dataGrid, out ScrollViewer scrollViewer))
{
this.Dispatcher.InvokeAsync(() =>
{
scrollViewer.ScrollToHorizontalOffset(this.OriginalScrollPosition);
this.IsResizingColumn = false;
}, DispatcherPriority.Background);
}
}
private void DataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
{
var dataGridCell = sender as DataGridCell;
if (TryFindVisualChildElement(this.DataGrid, out ScrollViewer scrollViewer))
{
this.OriginalScrollPosition = scrollViewer.HorizontalOffset;
this.IsResizingColumn = true;
}
}
private bool TryFindVisualChildElement<TChild>(DependencyObject parent, out TChild resultElement)
where TChild : DependencyObject
{
resultElement = null;
if (parent is Popup popup)
{
parent = popup.Child;
if (parent == null)
{
return false;
}
}
for (var childIndex = 0; childIndex < VisualTreeHelper.GetChildrenCount(parent); childIndex )
{
DependencyObject childElement = VisualTreeHelper.GetChild(parent, childIndex);
if (childElement is TChild child)
{
resultElement = child;
return true;
}
if (TryFindVisualChildElement(childElement, out resultElement))
{
return true;
}
}
return false;
}