使用MVVM设计模式将焦点移到WPF DataGrid中Enter键上的下一个单元格上吗?

时间:2019-08-06 02:37:45

标签: c# wpf xaml mvvm datagrid

我正在编写一个简单的wpf应用程序,其中包含datagrid。我正在遵循MVVM设计模式。最初运行应用程序时,将在数据网格中添加一个空行,默认情况下,我将焦点放在第一行的第一单元格上。

我需要完成以下工作,并且需要使用MVVM设计模式来完成它。

  1. 按“ Enter”键时,将焦点移到下一个单元格
  2. 当焦点设置为网格的最后一个单元格并且用户再次按下“ Enter”键时,应将新的空行添加到网格,并将焦点添加到新行的第一个单元格。
  3. li>

我发现了一些类似的问题(例如this),但是他们都没有解释如何使用MVVM设计模式来做到这一点,而我的第二点未包含在这些帖子中。

Item.cs类如下。

fail

ItemsViewModel.cs类如下。

public class Item
{
    public string ItemCode { get; set; }
    public string ItemName { get; set; }
    public double ItemPrice { get; set; }

    public Item(string itemCode,string itemName, double itemPrice)
    {
        this.ItemCode = itemCode;
        this.ItemName = itemName;
        this.ItemPrice = itemPrice;
    }
}

在应用初始化时,跟随DataGridBehavior.cs类将处理第一个单元格的焦点。

public class ItemsViewModel : INotifyPropertyChanged
{
    private List<Item> _items;

    public List<Item> ItemsCollection
    {
        get { return this._items; }
        set
        {
            _items = value;
            OnPropertyChanged(nameof(ItemsCollection));
        }
    }

    public ItemsViewModel()
    {
        this.ItemsCollection = new List<Item>();
        this.ItemsCollection.Add(new Item("", "", 0));
    }

    #region INotifyPropertyChanged Implementations

    public event PropertyChangedEventHandler PropertyChanged;

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

    #endregion
}

Items.xaml用户控件如下。

public static class DataGridBehavior
{
    public static readonly DependencyProperty FocusFirstCellProperty = DependencyProperty.RegisterAttached(
        "FocusFirstCell", typeof(Boolean), typeof(DataGridBehavior), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnFocusFirstCellChanged)));

    public static void SetFocusFirstCell(DataGrid element, Boolean value)
    {
        element.SetValue(FocusFirstCellProperty, value);
    }

    public static Boolean GetFocusFirstCell(DataGrid element)
    {
        return (Boolean)element.GetValue(FocusFirstCellProperty);
    }

    private static void OnFocusFirstCellChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DataGrid element = (DataGrid)d;
        if (element.IsLoaded)
        {
            TextBox textBox = FindVisualChild<TextBox>(element);
            if (textBox != null)
                Keyboard.Focus(textBox);
        }
        else
        {
            RoutedEventHandler handler = null;
            handler = (ss, ee) =>
            {
                DataGrid dataGrid = (DataGrid)ss;
                TextBox textBox = FindVisualChild<TextBox>((DataGrid)ss);
                if (textBox != null)
                    Keyboard.Focus(textBox);
                dataGrid.Loaded -= handler;
            };
            element.Loaded += handler;
        }
    }

    private 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;
    }
}

MainWindow.xaml如下

<UserControl x:Class="WpfApp2.Items"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
         xmlns:local="clr-namespace:WpfApp2"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<Grid>
    <StackPanel Orientation="Vertical">
        <TextBlock>Search</TextBlock>
        <TextBox Text="{Binding Description}" />
        <DataGrid x:Name="grdItems" ItemsSource="{Binding ItemsCollection}" AutoGenerateColumns="False" ColumnWidth="*" 
                  local:DataGridBehavior.FocusFirstCell="True">
            <DataGrid.Columns>
                <DataGridTemplateColumn Header="Item Code">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox x:Name="txtItemCode" Text="{Binding ItemCode}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Item Name">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox x:Name="txtItemName" Text="{Binding ItemName}" />
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
                <DataGridTemplateColumn Header="Price">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <TextBox x:Name="txtItemSellingPrice" Text="{Binding ItemPrice}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </StackPanel>
</Grid>

1 个答案:

答案 0 :(得分:1)

此方法正常运行

dvSalesEntryDataGrid.PreviewKeyDown += Datagrid_PreviewKeyDown;

添加Datagrid PreviewKeyDown事件

if (e.Key == Key.Enter)
            {
   if (Keyboard.FocusedElement is UIElement elementWithFocus)
                {
                    switch (dvDataGrid.CurrentCell.Column.DisplayIndex)
                    {
                            case 1:
                            DataGridRow currentrow5 = dvDataGrid.ItemContainerGenerator.ContainerFromItem(dvDataGrid.CurrentItem) as DataGridRow;
                            elementWithFocus.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));                             
                            break;
                            case 2:
                            DataGridRow currentrow5 = dvDataGrid.ItemContainerGenerator.ContainerFromItem(dvDataGrid.CurrentItem) as DataGridRow;
                            elementWithFocus.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));                             
                            break;
                            case n:
                            if (dvDataGrid.ItemsSource is ObservableCollection<DetailinfoModel> itemsSourcelast)
                            {
                                DataGridRow currentrow35 = dvDataGrid.ItemContainerGenerator.ContainerFromItem(dvDataGrid.CurrentItem) as DataGridRow;
                                var newItem = new DetailinfoModel();
                                itemsSourcelast.Add(newItem);

                                dvDataGrid.SelectedItem = newItem;
                                Dispatcher.BeginInvoke(new Action(() =>
                                {
                                    DataGridRow newRow = dvDataGrid.ItemContainerGenerator.ContainerFromItem(newItem) as DataGridRow;
                                    DataGridCell cell = Helper.Helper.GetCell(dvSalesEntryDataGrid, newRow, 1);
                                    if (cell != null)
                                        dvDataGrid.CurrentCell = new DataGridCellInfo(cell);
                                }), DispatcherPriority.Background);
                                }
                            break;                               break;
                            default:
                            DataGridRow CurrentRowsdeault = dvDataGrid.ItemContainerGenerator.ContainerFromItem(dvDataGrid.CurrentItem) as DataGridRow;
                            elementWithFocus.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));  
                            break;

          }
  }

}