我正在使用MVVM设计模式编写简单的WPF应用程序。我的应用程序包含一个具有单个datagrid视图的用户控件。数据网格的每个单元格都是一个文本框列。
我想要设置焦点在数据网格视图中第一个单元格的文本框。
我尝试了this解决方案及其在文本框中的工作。但是它不适用于网格单元格内的文本框。
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));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Item.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">
<DataGrid x:Name="grdItems" ItemsSource="{Binding ItemsCollection}" AutoGenerateColumns="False" ColumnWidth="*">
<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>
答案 0 :(得分:2)
了解FocusManager的工作方式。 :)
如果您需要一些示例的非正式描述,请查看here
示例:
<TextBox FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}" />
答案 1 :(得分:2)
您可以实现一种附加行为,即在加载TextBox
后在视觉树中找到DataGrid
:
public static class DataGridBehavior
{
public static readonly DependencyProperty FocusFirstCellProperty = DependencyProperty.RegisterAttached(
"FocusFirstCell", typeof(Boolean), typeof(DataGridBehavior), new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnChanged)));
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 OnChanged(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;
}
}
用法:
<DataGrid x:Name="grdItems" ItemsSource="{Binding ItemsCollection}"...
local:DataGridBehavior.FocusFirstCell="True">