当用户在最后一行的最后一个单元格上按Enter键时,向DataGrid添加一个新行

时间:2014-04-26 19:23:15

标签: c# wpf datagrid

我有一个包含3列的DataGrid。

当用户在DataGrid的最后一个单元格上点击 Enter 时,我想向DataGrid添加一个新行。我已经使用DataGrid.InputBindings成功完成了所有操作,但问题是当我在第二列上按 Enter 键时,会添加一个新行。我希望在焦点位于属于第3列的单元格时添加,然后按Enter键。

这是我的代码:

<DataGrid CanUserAddRows="False" CanUserDeleteRows="True" CanUserReorderColumns="False" CanUserResizeColumns="False" AutoGenerateColumns="False" 
          ItemsSource="{Binding People}" SelectedItem="{Binding SelectedRow}" CurrentCell="{Binding SelectedCell, Mode=OneWayToSource}" 
          DataGridCell.GotFocus="DataGrid_CellGotFocus" SelectionMode="Single">
    <DataGrid.InputBindings>
        <KeyBinding Key="Enter" Command="{Binding DataContext.NewRowCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
    </DataGrid.InputBindings>
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Confirmation" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <ComboBox SelectedItem="{Binding DataContext.SelectedConfirmation, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"
                              Visibility="{Binding DataContext.ConfirmationVisibility, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Converter={StaticResource boolToVisibilityConverter}}">
                        <ComboBox.Items>
                            <sys:String>Add New</sys:String>
                            <sys:String>End Of List</sys:String>
                        </ComboBox.Items>
                    </ComboBox>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Name" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding Name}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
        <DataGridTemplateColumn Header="Age" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Age}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
            <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                    <TextBox Text="{Binding Age}"/>
                </DataTemplate>
            </DataGridTemplateColumn.CellEditingTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

在视图模型中:

public class MainWindowViewModel : INotifyPropertyChanged
{

    public MainWindowViewModel()
    {
        People = new ObservableCollection<Person>();
        People.Add(new Person());

        NewRowCommand = new RelayCommand(NewRow);

    }

    private ObservableCollection<Person> _people;
    public ObservableCollection<Person> People
    {
        get
        {
            return _people;
        }
        set
        {
            _people = value;
            OnPropertyChanged("People");
        }
    }

    private Person _selectedRow;
    public Person SelectedRow
    {
        get
        {
            return _selectedRow;
        }
        set
        {
            _selectedRow = value;
            OnPropertyChanged("SelectedRow");

            if (_selectedRow == People.Last())
            {
                ConfirmationVisibility = true;
            }
            else
            {
                ConfirmationVisibility = false;
            }
        }
    }

    private bool _confirmationVisibility;
    public bool ConfirmationVisibility
    {
        get
        {
            return _confirmationVisibility;
        }
        set
        {
            _confirmationVisibility = value;
            OnPropertyChanged("ConfirmationVisibility");
        }
    }

    private string _selectedConfirmation;
    public string SelectedConfirmation
    {
        get
        {
            return _selectedConfirmation;
        }
        set
        {
            _selectedConfirmation = value;
            OnPropertyChanged("SelectedConfirmation");
        }
    }

    private DataGridCellInfo _selectedCell;
    public DataGridCellInfo SelectedCell
    {
        get
        {
            return _selectedCell;
        }
        set
        {
            _selectedCell = value;
            OnPropertyChanged("SelectedCell");
        }
    }

    public ICommand NewRowCommand { get; set; }

    private void NewRow(object obj)
    {
        if (SelectedRow == People.Last())
        {
            if (SelectedConfirmation == "Add New")
            {
                if (SelectedCell.Column.Header.ToString() == "Age")
                {
                    People.Add(new Person());
                }
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

以下是在VS2012中创建的示例项目:https://drive.google.com/file/d/0B5WyqSALui0bWVNHcVFXU1hOQ00/edit?usp=sharing

3 个答案:

答案 0 :(得分:2)

任何UIElement都可以InputBindings,而不只是DataGrid。所以为什么不搬家

<DataGrid.InputBindings>
    <KeyBinding Key="Enter" Command="{Binding DataContext.NewRowCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
</DataGrid.InputBindings>

到您想要的列:

    <DataGridTemplateColumn Header="Age" Width="*">
        <DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Age}">
                    <TextBlock.InputBindings>
                        <KeyBinding Key="Enter" Command="{Binding DataContext.NewRowCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
                    </TextBlock.InputBindings>
                </TextBlock>
            </DataTemplate>
        </DataGridTemplateColumn.CellTemplate>
        <DataGridTemplateColumn.CellEditingTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Age}">
                    <TextBox.InputBindings>
                        <KeyBinding Key="Enter" Command="{Binding DataContext.NewRowCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}"/>
                    </TextBox.InputBindings>
                </TextBox>
            </DataTemplate>
        </DataGridTemplateColumn.CellEditingTemplate>
    </DataGridTemplateColumn>

答案 1 :(得分:2)

当您按Enter键时,它会立即进入第3列而不是在您选择标题时创建列==年龄在等于确认时创建它。 这是您修改的工作代码,用于修复错误

private void NewRow(object obj)
{
    if (SelectedRow == People.Last())
    {
        if (SelectedConfirmation == "Add New")
        {
            if (SelectedCell.Column.Header.ToString() == "Confirmation")
            {
                People.Add(new Person());
            }
        }
    }
}

只需执行此操作,当用户按下最后一列时,您的示例将使用新行创建 希望你的问题得到解决,并为自己赢得了第一个答案和积分。

答案 2 :(得分:2)

代码的问题在于CurrentCell属性绑定。 它在调用NewRowCommand之前绑定新的当前单元格。

让我们假设你在哪里&#34;姓名&#34;最后一行的列,所以会发生什么:

  1. 按下回车键。
  2. 使用新单元格更新当前单元格。 (年龄)
  3. 然后调用您的命令,并使用新的当前单元格(Age),从而添加新行。
  4. 我建议在currentcell更新时保留对前一个单元格的引用。并使用它而不是currentCell。

     public DataGridCellInfo SelectedCell
        {
            get
            {
                return _selectedCell;
            }
            set
            {
                _lastCell = _selectedCell; //here is my edit
                _selectedCell = value;
                OnPropertyChanged("SelectedCell");
            }
        }
    

    所以新的NewRow(对象obj)看起来像这样:

     private void NewRow(object obj)
        {
            if (SelectedRow == People.Last())
            {
                if (SelectedConfirmation == "Add New")
                {
                    if (_lastCell.Column !=null && _lastCell.Column.Header.ToString() =="Age")//here is my edit
                    {
                        People.Add(new Person());
                    }
                }
            }
        }
    

    DataGrid_CellGotFocus(对象发送者,RoutedEventArgs e)中也存在问题。看看我的编辑,我放弃了行。我选择了分配。

     private void DataGrid_CellGotFocus(object sender, RoutedEventArgs e)
        {
            // Lookup for the source to be DataGridCell
            if (e.OriginalSource.GetType() == typeof(DataGridCell))
            {
                // Starts the Edit on the row;
                DataGrid grd = (DataGrid)sender;
                grd.BeginEdit(e);
    
                Control control = GetFirstChildByType<Control>(e.OriginalSource as DataGridCell);
                if (control != null)
                {
                    control.Focus();
                }
    
                DataGridCell cell = GetDataGridCell(grd.CurrentCell);
                DataGrid dataGrid = FindVisualParent<DataGrid>(cell);
                if (dataGrid != null)
                {
                    if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
                    {
                        if (!cell.IsSelected)
                            cell.IsSelected = true;
                    }
                }
            }
        }
    

    我在电脑上运行了编辑过的代码,效果很好!如果我可能错过任何问题,请告诉我。