WPF datagrid,autocompletebox单元格

时间:2015-10-03 18:24:05

标签: wpf datagrid autocomplete

我有一个数据网格,其中有一个AutoCompleteBox 我希望当我将焦点切换到包含ACB的单元格时,它会直接进入输入模式。目前我必须按回车键才能完成。 这里是代码:

   <DataGrid Grid.ColumnSpan="3"
                AutoGenerateColumns="False" 
                HorizontalAlignment="Stretch" 
                VerticalAlignment="Stretch"
                IsSynchronizedWithCurrentItem="True"
                RowHeight="30"
                Grid.Column="0" 
                SelectionUnit="Cell"
                ItemsSource="{Binding  RowsToEdit, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" 

                SelectedItem="{Binding SelectedPerson, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                b:DataGridEnterKeyBehavior.EnterKeyNexCellProperty="True"
                b:DataGridEnterEditOnCellGotFocus.EnterEditOnGotFocusProperty="True" Margin="0,45,0,5" Grid.RowSpan="2"

              >


        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Code, UpdateSourceTrigger=PropertyChanged,  Mode=TwoWay, StringFormat=\{0:#\}}"  Header="Code" >
                <i:Interaction.Triggers>
                    <i:EventTrigger EventName="PreviewKeyDown">
                        <gs:EventToCommand Command="{Binding HandleCellKeyDownCommand, Source={StaticResource MyViewModel}}"
                                           PassEventArgsToCommand="True"

                                           />
                    </i:EventTrigger>
                </i:Interaction.Triggers>
            </DataGridTextColumn>
            <DataGridTemplateColumn Header="Name" >

                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Nom}"/>
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
                <!--FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}" -->
                <DataGridTemplateColumn.CellEditingTemplate>
                    <DataTemplate>

                        <controls:AutoCompleteBox
                                x:Name="acb2"
                                Text="{Binding Nom, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 
                                ItemsSource="{Binding Names,Source={StaticResource MyViewModel}}" 
                                SelectedItem="{Binding Path=SelectedPerson, Source={StaticResource MyViewModel}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
                                ValueMemberBinding="{Binding Nom}"
                                Style="{StaticResource acbStyle}"
                                ItemTemplate="{StaticResource AutoCompleteBoxItemTemplate}"

                                >
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="SelectionChanged">
                                    <gs:EventToCommand Command="{Binding SelectionChangedCommand, Source={StaticResource MyViewModel}}" 
                                           CommandParameter="{Binding Path=SelectedPerson, Source={StaticResource MyViewModel}}"
                                           />
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </controls:AutoCompleteBox>
                    </DataTemplate>
                </DataGridTemplateColumn.CellEditingTemplate>

            </DataGridTemplateColumn>

            <DataGridTextColumn Binding="{Binding Adresse, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"       Header="Adresse" />

        </DataGrid.Columns>
    </DataGrid>




//Behaviors
    //Behavior for passing automatically in edit mode when cell get focus
  public static class DataGridEnterEditOnCellGotFocus
{


    public static readonly DependencyProperty EnterEditOnGotFocusProperty =
     DependencyProperty.RegisterAttached("EnterEditOnGotFocus",
     typeof(bool),
     typeof(DataGridEnterEditOnCellGotFocus),
     new UIPropertyMetadata(false, ProcessCellGotFocusEnter));



    public static bool GetEnterEditOnGotFocusProperty(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnterEditOnGotFocusProperty);
    }

    public static void SetEnterEditOnGotFocusProperty(DependencyObject obj, bool value)
    {
        obj.SetValue(EnterEditOnGotFocusProperty, value);
    }



    private static void ProcessCellGotFocusEnter(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DataGrid dg = (d as DataGrid);

        if (dg != null)
        {
            if ((bool)e.NewValue)
                dg.GotFocus += dg_GotFocus;
            else
                dg.GotFocus -= dg_GotFocus;
        }
    }


    private static void dg_GotFocus(object sender, RoutedEventArgs e)
    {


        if (e.OriginalSource.GetType() == typeof(DataGridCell))
        {

            DataGridCell source = e.OriginalSource as DataGridCell;

            DataGrid grd = (DataGrid)sender;
            grd.BeginEdit(e);

            Control control = GetFirstChildByType<Control>(source);
            if (control != null)
            {

                control.Focus();

             }
        }
    }

//Behaviors for moving from cell to another with entre key
public static class DataGridEnterKeyBehavior
{


    public static readonly DependencyProperty EnterKeyNexCellProperty =
     DependencyProperty.RegisterAttached("EnterKeyNexCell",
     typeof(bool),
     typeof(DataGridEnterKeyBehavior),
     new UIPropertyMetadata(false, ProcessEnterKeyDown));



    public static bool GetEnterKeyNexCellProperty(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnterKeyNexCellProperty);
    }

    public static void SetEnterKeyNexCellProperty(DependencyObject obj, bool value)
    {
        obj.SetValue(EnterKeyNexCellProperty, value);
    }



    private static void ProcessEnterKeyDown(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DataGrid dg = (d as DataGrid);

        if (dg != null)
        {
            if ((bool)e.NewValue)
                dg.PreviewKeyDown += dg_PreviewKeyDownDatagrid;
            else
                dg.PreviewKeyDown -= dg_PreviewKeyDownDatagrid;
        }
    }


    private static void dg_PreviewKeyDownDatagrid(object sender, KeyEventArgs e)
    {

        DataGrid dg = (sender as DataGrid);

        var uiElement = e.OriginalSource as UIElement;
        if (e.Key == Key.Enter && uiElement != null)
        {
            e.Handled = true;
            dg.SelectedCells.Clear();
            uiElement.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            dg.BeginEdit();

        }

    }
}

ViewModel

public class MyViewModel : ObservableObject
{
    ObservableCollection<Person> _names = null;
    ObservableCollection<Person> _rowsToEdit = null;

    public ObservableCollection<Person> RowsToEdit
    {
        get { return _rowsToEdit; }
        set
        {
            _rowsToEdit = value;
            RaisePropertyChanged("RowsToEdit");
        }
    }

    RelayCommand _loadClients;
    RelayCommand _showSelectedPerson;
    RelayCommand<Person> _selectchangedcommand;
    RelayCommand<KeyEventArgs> _handleCellKeyDown;

    Person _selectedPerson;




    public Person SelectedPerson
    {
        get { return _selectedPerson; }
        set
        {
            _selectedPerson = value;
            RaisePropertyChanged("SelectedPerson");
        }
    }



    public ObservableCollection<Person> Names
    {
        get { return _names; }
        set
        {
            _names = value;
            RaisePropertyChanged("Names");
        }
    }




    public RelayCommand LoadClientCommand
    {
        get
        {
            if (_loadClients == null)
                _loadClients = new RelayCommand(LoadCommandExecute);
            return _loadClients;
        }
    }



    private void LoadCommandExecute()
    {
        LoadClients();
        List<Person> ll = new List<Person>(1);
        ll.Add(new Person(0, "", ""));
        RowsToEdit = new ObservableCollection<Person>(ll);
    }



    public void LoadClients()
    {
        List<Person> ll = new List<Person>(8);
        ll.Add(new Person(1, "AAAAAAA", "Adresse1"));
        ll.Add(new Person(2, "AABBBBB", "Adresse 2"));
        ll.Add(new Person(3, "AAACCCC", "Adresse3"));
        ll.Add(new Person(4, "BBBBHHHH", "Adresse4"));
        ll.Add(new Person(5, "BBBCGGFR", "Adresse5"));
        ll.Add(new Person(6, "JJJJJHHGYGH", "Adresse6"));
        ll.Add(new Person(7, "HHHHHHHHGGG", "Adresse7"));
        ll.Add(new Person(8, "AAAAHHGBV", "Adresse8"));

        Names = new ObservableCollection<Person>(ll);

    }



    public RelayCommand ShowSelectedPersonCommand
    {
        get
        {
            if (_showSelectedPerson == null)
                _showSelectedPerson = new RelayCommand(ShowSelectedPersonCommandExecute);
            return _showSelectedPerson;
        }
    }



    private void ShowSelectedPersonCommandExecute()
    {
        if (SelectedPerson != null)
            MessageBox.Show(SelectedPerson.Nom);
        else
            MessageBox.Show("No sslections.");

    }


    public RelayCommand<Person> SelectionChangedCommand
    {
        get
        {
            if (_selectchangedcommand == null)
                _selectchangedcommand = new RelayCommand<Person>(SelectionChangedCommandExecute);
            return _selectchangedcommand;
        }
    }


    private void SelectionChangedCommandExecute(Person SelectedPerson)
    {
        /*if (SelectedPerson != null)
            MessageBox.Show(SelectedPerson.Code.ToString());
        else
            MessageBox.Show("Pas de sélection.");
        */

    }


  }

2 个答案:

答案 0 :(得分:0)

  1. 您必须处理数据网格的PreviewGotFocus。
  2. 您必须使用DataGrid:BeginEdit()才能进入编辑模式。
  3. 当按下ENTER时,我们发现当前行中的下一个单元格会进一步移动。
  4. 一旦我们到达当前行的最后一个单元格,按ENTER键将焦点移动到下一行的第一个单元格。
  5. 一旦我们最后一行的单元格,按ENTER键将焦点移动到第一行的第一个单元格。
  6. 见下面的例子。它使用名为dgrdInvoice的DataGrid。

     private void dgrdInvoice_PreviewGotFocus(object sender, RoutedEventArgs e)
        {
            if (e.OriginalSource is DataGridCell)
            {               
                DataGridCell cell = (DataGridCell)e.OriginalSource;
    
                Debug.WriteLine(cell.ToString());
    
                RoutedEventHandler gotFocusHandler = new RoutedEventHandler(DataGridCell_GotFocus);
                cell.GotFocus -= gotFocusHandler;
                cell.GotFocus += gotFocusHandler;
    
                KeyEventHandler previewKeyDownHandler = new KeyEventHandler(DataGridcell_PreviewKeyDown);
                cell.PreviewKeyDown -= previewKeyDownHandler;
                cell.PreviewKeyDown += previewKeyDownHandler;
            }
        }
    
        void DataGridCell_GotFocus(object sender, RoutedEventArgs e)
        {
            DataGridCell cell = (DataGridCell)sender;
    
            dgrdInvoice.CurrentCell = new DataGridCellInfo((DataGridCell)sender);
            dgrdInvoice.BeginEdit();
    
            Debug.WriteLine("got focus" + cell.ToString());
            e.Handled = true;
        }
    
        void DataGridcell_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
        {
            DataGridCell cell = (DataGridCell)sender;
            DataGridCellsPresenter cellsPresenter = (DataGridCellsPresenter)DataGridCellsPresenter
                                                                                .ItemsControlFromItemContainer(cell);
            int cellCount = cellsPresenter.Items.Count;
            int currCellIndex = dgrdInvoice.CurrentColumn.DisplayIndex;
    
            DataGridRow rowContainer = (DataGridRow)DataGridCellsPresenter.ContainerFromElement(dgrdInvoice, cell);
    
            DataGridCell nextCell;
    
            if (e.Key == Key.Enter || e.Key == Key.Escape)
            {
                if (currCellIndex < cellCount - 1)
                {
                    nextCell = GetCell(dgrdInvoice, rowContainer, currCellIndex + 1); // get next cell
                }
                else
                {
                    currCellIndex = -1;
    
                    nextCell = GetCell(dgrdInvoice, GetNextRow(dgrdInvoice, rowContainer), currCellIndex + 1); // get next cell
                }
    
                if(e.Key == Key.Escape)
                {
                    dgrdInvoice.CancelEdit();
                }
    
                e.Handled = true;
                nextCell.Focus();
                dgrdInvoice.BeginEdit();
            }
        }
    
        #region DataGrid Navigation Helper
    
        public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(obj, i);
                if (child != null && child is T)
                    return (T)child;
                else
                {
                    T childOfChild = FindVisualChild<T>(child);
                    if (childOfChild != null)
                        return childOfChild;
                }
            }
            return null;
        }
    
        public static DataGridRow GetNextRow(System.Windows.Controls.DataGrid dataGrid, DataGridRow currRow)
        {
            DataGridRow nextRow = null;
    
            for (int i = 0; i < dataGrid.Items.Count; ++i)
            {
                DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(i);
    
                if (row.Equals(currRow))
                {
                    nextRow = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(i + 1);
                    if (nextRow.IsNewItem)
                        nextRow = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(0);
    
                    break;
                }
            }
    
            return nextRow;
        }
    
        public static DataGridCell GetCell(System.Windows.Controls.DataGrid dataGrid, DataGridRow rowContainer, int column)
        {
            if (rowContainer != null)
            {
                DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(rowContainer);
                if (presenter == null)
                {
                    /* if the row has been virtualized away, call its ApplyTemplate() method 
                     * to build its visual tree in order for the DataGridCellsPresenter
                     * and the DataGridCells to be created */
                    rowContainer.ApplyTemplate();
                    presenter = FindVisualChild<DataGridCellsPresenter>(rowContainer);
                }
                if (presenter != null)
                {
                    DataGridCell cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
                    if (cell == null)
                    {
                        /* bring the column into view
                         * in case it has been virtualized away */
                        dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]);
                        cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
                    }
                    return cell;
                }
            }
            return null;
        }
    
        #endregion
    

答案 1 :(得分:0)

最后我找到了一个解决方案,也许还有其他更好的解决方案。 问题在于在ACB中选择控制“文本”。所以改变行为如下解决问题。这里代码:

   private static void dg_GotFocus(object sender, RoutedEventArgs e)
    {


        if (e.OriginalSource.GetType() == typeof(DataGridCell))
        {
            // Starts the Edit on the row;
            DataGridCell source = e.OriginalSource as DataGridCell;


            DataGrid grd = (DataGrid)sender;

            grd.BeginEdit(e);

            source.IsEditing = true;

            Control control = GetFirstChildByType<Control>(source);
            if (control != null)
            {
                //Here i Check if control is an ACB, if it is
               //Try to access to Control "Text" inside it and that's all
                if (control.GetType() == typeof(AutoCompleteBox))
                {
                    control = GetFirstChildByType<Control>(control);
                }

            }
          if (control != null)
                control.Focus();


            e.Handled = true;
        }
    }