删除DataGrid中的自动生成的行

时间:2014-07-05 18:36:26

标签: c# wpf xaml mvvm datagrid

我有一个DataGrid。它被绑定到名为People的Person的集合。

允许用户添加新行,我的意思是CanUserAddRows = true

在我的DataGrid中输入键作为 TAB 键。

我的DataGrid有三列,分别是:FirstName,LastName,City。 FirstName是必需的。另外两个不是强制性的。

当用户在最后一行的第一个单元格(自动生成的行)上点击 Enter 时,如果该单元格为空,则计算机猜测该用户不想向DataGrid添加更多数据并且焦点移动到DataGrid外部的按钮。

到目前为止,一切正常。

问题:

在最后一行的第一个单元格中按 Enter 并保持为空,DataGrid外部的按钮会被聚焦。那时我不希望用户看到DataGrid中的最后一个空行。

我尝试了什么:

我尝试过两个事件:1。GotFocus和2. LostFocus

在DataGrid的GotFocus事件中,我设置了CanUserAddRows = true 在DataGrid的LostFocus事件中,我设置了CanUserAddRows = false

但不幸的是,当DataGrid的内容中的textBlock成为焦点时,DataGrid认为它失去了焦点。因此,CanUserAddRows设置为false,我收到错误。

我的代码:

person.cs

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string City { get; set; }
}

MainWindowViewModel.cs

public class MainWindowViewModel : INotifyPropertyChanged
{
    public MainWindowViewModel()
    {
        People = new ObservableCollection<Person>();
    }

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

    public event PropertyChangedEventHandler PropertyChanged;

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

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="MainWindow" Height="350" Width="525">

    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="65*"/>
            <ColumnDefinition Width="9*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="93*"/>
            <RowDefinition Height="14*"/>
        </Grid.RowDefinitions>
        <DataGrid x:Name="maindg" AutoGenerateColumns="True" ItemsSource="{Binding People}" Margin="0,0,0.4,-0.2" Grid.RowSpan="2" Grid.ColumnSpan="2" 
                  PreviewKeyDown="DataGrid_KeyDown_1" SelectedIndex="0" GridLinesVisibility="Vertical" 
                  SelectionMode="Single" SelectionUnit="CellOrRowHeader" >
        </DataGrid>

        <Button Height="20" Width="50" Content="Save" Margin="2.8,9.8,10.4,11.8" Grid.Column="1" Grid.Row="1" x:Name="btnSave" />
    </Grid>
</Window>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private int FindRowIndex(DataGridRow row)
    {
        DataGrid dataGrid =
            ItemsControl.ItemsControlFromItemContainer(row)
            as DataGrid;

        int index = dataGrid.ItemContainerGenerator.
            IndexFromContainer(row);

        return index;
    }

    private object ExtractBoundValue(DataGridRow row,
                             DataGridCell cell)
    {
        // find the column that this cell belongs to
        DataGridBoundColumn col =
           cell.Column as DataGridBoundColumn;

        // find the property that this column is bound to
        Binding binding = col.Binding as Binding;
        string boundPropertyName = binding.Path.Path;

        // find the object that is related to this row
        object data = row.Item;

        // extract the property value
        PropertyDescriptorCollection properties =
            TypeDescriptor.GetProperties(data);

        PropertyDescriptor property = properties[boundPropertyName];
        if (property != null)
        {
            object value = property.GetValue(data);

            return value;
        }

        return null;
    }

    private void DataGrid_KeyDown_1(object sender, KeyEventArgs e)
    {
        if (e.Key != Key.Enter) return;

        DependencyObject dep = (DependencyObject)e.OriginalSource;
        //here we just find the cell got focused ...
        //then we can use the cell key down or key up
        // iteratively traverse the visual tree
        while ((dep != null) && !(dep is DataGridCell) && !(dep is DataGridColumnHeader))
        {
            dep = VisualTreeHelper.GetParent(dep);
        }

        if (dep == null)
            return;

        if (dep is DataGridCell)
        {
            try
            {
                //cancel if datagrid in edit mode
                maindg.CommitEdit();


                //Check if selected cell is on first column and last row
                if (maindg.CurrentColumn.DisplayIndex == 0)
                {
                    DependencyObject dep1 = dep;
                    while ((dep1 != null) && !(dep1 is DataGridRow))
                    {
                        dep1 = VisualTreeHelper.GetParent(dep1);
                    }

                    DataGridRow row = dep1 as DataGridRow;

                    if (FindRowIndex(row) == maindg.Items.Count - 1)
                    {
                        if (ExtractBoundValue(row, dep as DataGridCell) == null)
                        {
                            btnSave.Focus();
                            return;
                        }
                    }
                }
            }
            catch
            {
                maindg.CancelEdit();
            }
            //get current cell
            DataGridCell cell = dep as DataGridCell;
            //deselect current cell
            cell.IsSelected = false;
            //find next right cell
            var nextCell = cell.PredictFocus(FocusNavigationDirection.Right);
            //if next right cell null go for find next ro first cell
            if (nextCell == null)
            {
                DependencyObject nextRowCell;
                nextRowCell = cell.PredictFocus(FocusNavigationDirection.Down);
                //if next row is null so we have no more row Return;
                if (nextRowCell == null)
                {
                    nextRowCell = dep;
                    while ((nextRowCell as DataGridCell).PredictFocus(FocusNavigationDirection.Left) != null)
                        nextRowCell = (nextRowCell as DataGridCell).PredictFocus(FocusNavigationDirection.Left);
                    //change current cell
                    maindg.CurrentCell = new DataGridCellInfo(nextRowCell as DataGridCell);
                    //change selected cell
                    (nextRowCell as DataGridCell).IsSelected = true;
                    return;
                }
                //we do this because we cant use FocusNavigationDirection.Next for function PredictFocus
                //so we have to find it this way
                while ((nextRowCell as DataGridCell).PredictFocus(FocusNavigationDirection.Left) != null)
                    nextRowCell = (nextRowCell as DataGridCell).PredictFocus(FocusNavigationDirection.Left);
                //set new cell as next cell
                nextCell = nextRowCell;
            }

            //change current cell
            maindg.CurrentCell = new DataGridCellInfo(nextCell as DataGridCell);
            //change selected cell
            (nextCell as DataGridCell).IsSelected = true;
            // start edit mode
            maindg.BeginEdit();
        }
        //handl the default action of keydown
        e.Handled = true;
    }
}

1 个答案:

答案 0 :(得分:2)

你快到了。在 GotFocus() 上,只需将 CanUserAddRows 设置为 True 即可。在 LostFocus() 处理程序中将其设置为 False

由于当焦点在网格中移动时也会调用LostFocus处理程序,因此您可以检查属性 IsKeyboardFocusWithin 以了解焦点是否在网格内。

private void maindg_GotFocus(object sender, RoutedEventArgs e)
{
    if (!maindg.CanUserAddRows)
    {
        maindg.CanUserAddRows = true;
    }
}

private void maindg_LostFocus(object sender, RoutedEventArgs e)
{
    if (!maindg.IsKeyboardFocusWithin && maindg.CanUserAddRows)
    {
        maindg.CanUserAddRows = false;
    }
}