In WinForm DataGridView, it automatically selects the first row when initialized. It drove me crazy when I tried to turn that feature off. Moving to WPF DataGrid, it seems M
I'm glad to report I found a solution for this problem through ItemContainerGenerator.StatusChanged
event.
dataGrid.ItemContainerGenerator.StatusChanged += new EventHandler(ItemContainerGenerator_StatusChanged);
void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
{
if (dataGrid.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
dataGrid.SelectedIndex = 0;
}
}
It looks when this event is fired with status ContainersGenerated, dataGrid is fully initialized. To me, this is more like DataGridView's DataBindingComplete event in WinForm. If so, the "DataContextChanged
" event should really be called "DataContextChanging
" event.
This was inspired by a post here I accidently found while looking for another clue.
Set IsSynchronizedWithCurrentItem = "true"
.
EDIT:
To address your comment, I assume that your DataGrid's SelectionUnit is set to "Cell", is it? Okay, I'm not sure if this is the best solution but one thing you can do is handle the Loaded event for the DataGrid and manually set the selected cell in the code-behind. So you'll have something like this:
<DataGrid x:Name="dg" AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True"
SelectedCellsChanged="dg_SelectedCellsChanged" SelectionUnit="Cell"
Loaded="dg_Loaded">
...
</DataGrid>
Event-Handler:
private void dg_Loaded(object sender, RoutedEventArgs e)
{
if ((dg.Items.Count > 0) &&
(dg.Columns.Count > 0))
{
//Select the first column of the first item.
dg.CurrentCell = new DataGridCellInfo(dg.Items[0], dg.Columns[0]);
dg.SelectedCells.Add(dg.CurrentCell);
}
}
Note that this will only work if the DataGrid.SelectionUnit is set to "Cell". Otherwise, I believe it will throw an exception.
EDIT2:
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel>
<Button Click="Button_Click">Reset</Button>
<DataGrid x:Name="dg" AutoGenerateColumns="False" IsSynchronizedWithCurrentItem="True"
SelectionUnit="Cell"
DataContextChanged="dg_DataContextChanged"
ItemsSource="{Binding Items}"
Loaded="dg_Loaded">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Window>
Code-Behind:
namespace WpfApplication1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.LoadItems();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.LoadItems();
}
private void LoadItems()
{
this.DataContext = new { Items = new List<string> { "Item1", "Item2", "Item3" } };
this.SelectFirstItem();
}
private void dg_Loaded(object sender, RoutedEventArgs e)
{
SelectFirstItem();
}
void SelectFirstItem()
{
if ((dg.Items.Count > 0) &&
(dg.Columns.Count > 0))
{
//Select the first column of the first item.
dg.CurrentCell = new DataGridCellInfo(dg.Items[0], dg.Columns[0]);
dg.SelectedCells.Add(dg.CurrentCell);
}
}
private void dg_DataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
this.SelectFirstItem();
}
}
}
You can do this consistently in the DataGrid.Loaded event. Just obtain the first row and have the row fire the selection event.
void MyGridLoaded(...) {
DataGridRow r = yourGrid.ItemContainergenerator.ContainerFromIndex(0) as DataGridRow;
if(r != null) {
r.IsSelected = false;
r.IsSelected = true;
}
}
I'm not sure this is a bug because you may not be guaranteed to have selection events fire from your object until the control is loaded. Don't know.
You could try this.
this.dataGrid.SelectionMode = DataGridSelectionMode.Single;
// Selects the 4th row.
this.dataGrid.SelectedIndex = 3;