【问题标题】:Move Focus to Next Cell on Enter Key Press in WPF DataGrid using MVVM design pattern?使用 MVVM 设计模式在 WPF DataGrid 中按 Enter 键时将焦点移动到下一个单元格?
【发布时间】:2019-12-13 13:04:44
【问题描述】:

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

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

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

我发现了一些类似的问题(例如:this),但没有一个人解释了如何使用 MVVM 设计模式来做到这一点,并且我上面的第二点没有包含在这些帖子中。

Item.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;
    }
}

ItemsViewModel.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
}

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

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

Items.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>

MainWindow.xaml 如下

<Window x:Class="WpfApp2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp2"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <local:Items/>
</Grid>

【问题讨论】:

    标签: c# wpf xaml mvvm datagrid


    【解决方案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;
    
              }
      }
    

    }

    【讨论】:

      猜你喜欢
      • 2012-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-23
      • 1970-01-01
      • 2016-01-22
      • 2023-03-27
      • 2019-12-12
      相关资源
      最近更新 更多