views:

117

answers:

3

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 Microsoft has decided to turn this feature off, which is a good thing I think. However, I have hard time to enable this feature now. For some DataGrid, I want the first row to be selected automatically after grid is populated through data binding. There are some suggestions in Internet, but I couldn't make that work. I hope for better luck here.

+1  A: 

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();
        }
    }
}
karmicpuppet
Thanks very much for the tip. I just tried it. Setting it to true will make the first row of the DataGrid "Highlighted", but not selected. I need the SelectedCellsChanged event to be fired. So, how do I make this event to be fired as well?
miliu
See EDIT. Hope it helps.
karmicpuppet
@karmicpuppet: This code works in dg_Loaded event. However, it doens work in DataContextChanged event. Essentially, the same grid is reused. Each time when a data data context is set, I want to have the first row to be selected automatically which should trigger SelectedCellsChanged event because I'm relying on that.
miliu
@karmicpuppet again: I think this is related to my other question: Where is WPF DataGrid DataBindingComplete event? Somebody pointed me to DataContextChanged event. As I observed, DataContextChanged event is actually fired after I set a new data context. However, I cannot make the visual effect work in this event handler. Very strange.
miliu
I don't think there's a DataBindingComplete event in WPF. I'm not sure. How about trying out the "dataGrid.ItemContainerGenerator.ItemsChanged" event?
karmicpuppet
@karmicpuppet: Just tried it with DataGrid.ItemContainerGenerator.ItemsChanged event and the behavior seems to be same as DataContextChanged.
miliu
miliu, i think i'm running out of suggestions. sorry about that. but see, if i were to do something like this, i would typically use the MVVM pattern for my application. I'll have my items for the datagrid, and the selection state stored in a ViewModel. The UI will then bind to properties in the ViewModel. This may be the way to go, but might require a lot of work. Anyway, sorry my suggestions above didn't work out.
karmicpuppet
@karmicpuppet: I don't understand how MVVM could help me in this case. I only want to have the first row selected automatically when DataContext is changed. I really hate to write tons of code just for this seemly very simple task.
miliu
Ok, if really, what you want is to automatically select the first row when DataContext changes, then I believe my code above works. See EDIT2 above and try out the code. It works.
karmicpuppet
A: 

You could try this.

        this.dataGrid.SelectionMode = DataGridSelectionMode.Single;

        // Selects the 4th row.
        this.dataGrid.SelectedIndex = 3;
Avatar
This one is for row selection.
Avatar
@Avatar: I just tried your suggestion. It seems to have the same effect as IsSynchronizedWithCurrentItem. So, it just highlights the row, but I don't get SelectedCellsChanged event. Unfortunately, there is no "SelectedRowChanged" event or something like that. Compared to WinForm DataGridView, WPF DataGrid has very few events.
miliu
@miliu the SelectedCellsChanged event should get triggered don't know what issue is. I have a sample here. Please check that. That might give you some idea. http://www.filefactory.com/file/b3bhf1d/n/DataGridCheckBoxSelection.zip
Avatar
@Avatar: I can't get your file downloaded from FileFactory. It asked me to register to get rid of the popup ads. I did it, but it still pops up. I have to wait for 30 sec. I did, but then when I click, the whole cycle starts again, and it crashes my IE eventually. It crashed three times. I hate those webpages with tons of popups. Do they really make money from that?
miliu
do no those stuffs. i thought they are free. ok i've uploaded the file here https://sites.google.com/site/html5tutorials/DataGridCheckBoxSelection.zip this is lot more safe i guess
Avatar
@Avatar: Thanks for the sample, which helped me figure out my problem partially. Yes, the SelectedCellsChanged event does get fired. I just didn't noticed it because in my event handler I'm checking the CurrentCell which is not set. However, I do see another problem. If I put DataGrid.SelectedIndex = 0 in DataContextChanged event, it works the first time. But in the following times (when data context is changed), the selection highlight is not showing up. I need this visual clue to indicate which row is currently selected. I think this is more a problem of DataContextChanged event, see above.
miliu
A: 

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.

miliu