【发布时间】:2019-12-13 13:04:44
【问题描述】:
我正在编写一个包含数据网格的简单 wpf 应用程序。我正在遵循 MVVM 设计模式。当应用程序最初运行时,一个空行将添加到数据网格中,默认情况下我将关注第一行的第一个单元格。
我需要完成以下工作,并且需要使用 MVVM 设计模式来完成。
- 当您按“Enter”键时,将焦点移至下一个单元格
- 当焦点设置到网格的最后一个单元格并且用户再次按“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>
【问题讨论】: