【问题标题】:Datagrid Set focus on newly added rowDatagrid 将焦点设置在新添加的行上
【发布时间】:2010-07-22 10:39:09
【问题描述】:

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

我不知道如何使新添加的行使第一个单元格成为焦点,就好像我们正在编辑一样。我正在使用 MVVM 模式。

有什么想法或建议吗?

【问题讨论】:

    标签: wpf


    【解决方案1】:

    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() 开始。

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        【解决方案3】:

        你想做这样的事情:

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

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

        【讨论】:

          【解决方案4】:


          希望对其他人有所帮助。
          我将在视图中展示 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>
          

          现在在视图模型中:
          您需要在添加、删除等之后设置 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> 
          

          谢谢,阿维。

          【讨论】:

            【解决方案5】:

            对我有用的是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()

            【讨论】:

              【解决方案6】:

              感谢 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;
              }
              

              【讨论】:

                猜你喜欢
                • 2018-10-04
                • 1970-01-01
                • 2013-09-01
                • 2011-11-25
                • 1970-01-01
                • 1970-01-01
                • 2017-02-24
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多