Datagrid设置焦点在新添加的行上

时间:2010-07-22 10:39:10

标签: wpf

我有一个绑定到可观察集合的数据网格。 当用户按下“添加按钮”时,它会添加一个新行,我通过向observablecollection添加一个新元素来完成此操作。

我无法弄清楚如何使第一个单元格成为新添加的行,就像我们正在编辑一样。我正在使用MVVM模式。

有任何想法或建议吗?

6 个答案:

答案 0 :(得分:2)

The answer given by Gauss是正确的方法,但有了一些代码,它就更清晰了:

void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Loaded += Row_Loaded;
}

void Row_Loaded(object sender, RoutedEventArgs e)
{        
    var row = (DataGridRow) sender;
    row.Loaded -= Row_Loaded;
    DataGridCell cell = GetCell(dataGrid, row, 0);
    if (cell != null) cell.Focus();
    dataGrid.BeginEdit();        
}

static DataGridCell GetCell(DataGrid dataGrid, DataGridRow row, int column)
{
    if (dataGrid == null) throw new ArgumentNullException("dataGrid");
    if (row == null) throw new ArgumentNullException("row");
    if (column < 0) throw new ArgumentOutOfRangeException("column");

    DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(row);
    if (presenter == null)
    {
        row.ApplyTemplate();
        presenter = FindVisualChild<DataGridCellsPresenter>(row);
    }
    if (presenter != null)
    {
        var cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
        if (cell == null)
        {
            dataGrid.ScrollIntoView(row, dataGrid.Columns[column]);
            cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
        }
        return cell;
    }
    return null;
}

static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        var visualChild = child as T;
        if (visualChild != null)
            return visualChild;
        var childOfChild = FindVisualChild<T>(child);
        if (childOfChild != null)
            return childOfChild;
    }
    return null;
}

您检索DataGrid.LoadingRow事件中的行,但该单元格尚不可用。因此,您在Loaded事件上放置一个处理程序,以便等待此事件发生,然后您可以检索单元格并将焦点放在它上面。

删除处理程序以避免新的触发。

编辑会话也可以使用dataGrid.BeginEdit()启动。

所有这些都在代码隐藏中,因为它属于视图。

答案 1 :(得分:1)

尝试捕获DataGrid的LoadingRow(或类似)事件。在行上执行SetFocus(e.Row)(或类似)。这纯粹是面向View的,所以它符合MVVM。

答案 2 :(得分:0)

你想做这样的事情:

DataGridCell cell = GetCell(rowIndex, colIndex);
cell.Focus;

当然,您需要难以捉摸的GetCell()方法。来自MSFT的Vincent Sibal在this forum post中写了这个方法(以及所需的GetRow)。当我遇到这个时,我正在寻找别的东西,所以我没有使用它,但其他人似乎已经好运了。您会注意到有his blog的链接,您可能会发现这些链接对DataGrid相关的所有内容都有帮助。

答案 3 :(得分:0)


希望能帮助他人。
我将在视图中显示MVVM方式:

<DataGrid Name="dg1" ItemsSource="{Binding Table}" AutoGenerateColumns="False" Margin="3" SelectionMode="Single" IsReadOnly="True" SelectedIndex="{Binding Path=SelectedIndex, Mode=TwoWay}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Date"  Binding="{Binding mydate}" MinWidth="100"></DataGridTextColumn>
        <DataGridTextColumn Header="Count" Binding="{Binding Count}" MinWidth="100"></DataGridTextColumn>
    </DataGrid.Columns>

    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged" SourceName="dg1" >
            <i:InvokeCommandAction Command="{Binding DgSelectionChanged}" CommandParameter="{Binding ElementName=dg1}"/>
        </i:EventTrigger>

    </i:Interaction.Triggers>          
</DataGrid>

现在在View-Model中:
你需要在之后设置SelectedIndex:添加,删除等......和

 private ICommand dgSelectionChanged;
    /// <summary>
    /// when the datagrid Selection Changes
    /// </summary>
    public ICommand DgSelectionChanged
    {
        get
        {
            return dgSelectionChanged ??
            (dgSelectionChanged = new RelayCommand<DataGrid>(dg1 =>
            {
              // whatever you want when the Selection Changes


                SelectedIndex= d
                //select the item 
                if (dg1.SelectedIndex > -1)
                {
                    dg1.Focus();
                    dg1.CurrentCell = new DataGridCellInfo(dg1.Items[dg1.SelectedIndex], dg1.Columns[0]);
                }
            }));
        }
    }  

顺便说一下,要在加载控件后选择第一行,请将其添加到视图中:

        <!-- select the row after control loaded -->
        <i:EventTrigger EventName="Loaded" SourceName="dg1" >
            <i:InvokeCommandAction Command="{Binding DgSelectionChanged}" CommandParameter="{Binding ElementName=dg1}"/>  
        </i:EventTrigger>
    </i:Interaction.Triggers> 

谢谢,Avi。

答案 4 :(得分:0)

对我有用的是LoadingRowe.Row.Loaded和以下链接的GetCell()方法的组合:

http://social.technet.microsoft.com/wiki/contents/articles/21202.wpf-programmatically-selecting-and-focusing-a-row-or-cell-in-a-datagrid.aspx

通过DataGrid.LoadingRow在单元格可用之前调用GetCell事件。但是在DaraGridRow.Loaded事件中,单元格可用。

之后,您可以使用cell.Focus()DataGrid.BeginEdit()

答案 5 :(得分:0)

在我的案例中解决了这个问题,这要归功于杰克·伯格(Jake Berger)的回答。

绑定DataGrid的SelectedItem和处理LoadingRow事件的效果很好。

例如:

<DataGrid SelectionUnit="FullRow" SelectionMode="Single" ItemsSource="{Binding Source=MyList}" SelectedItem="{Binding SelectedDataItem, Mode=TwoWay}" LoadingRow="MyDataGrid_LoadingRow"></DataGrid>
private void MyDataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
          SelectedDataItem = (MyDataObject)e.Row.Item;
}