[英]Focus on specific cell in row programmatically via MVVM when observablecollection ItemSource changes WPF
I'm trying to set the focus on a specific cell in a row in my DataGrid.我正在尝试将焦点设置在 DataGrid 中一行中的特定单元格上。 The datagrid is bound to an observable collection of X. When I hit a specific button, it causes a new X to be inserted into the observable collection, but there is no focus on the datagrid's side of things and I want to focus the cursor so you can type in the newly created row (a specific cell in the row).
数据网格绑定到 X 的可观察集合。当我点击特定按钮时,它会导致将新 X 插入到可观察集合中,但是没有关注数据网格方面的事情,我想关注 cursor 所以您可以输入新创建的行(行中的特定单元格)。 Is this possible going the MVVM route?
这可能会走 MVVM 路线吗? My VM has the observable collection, so not too sure where to go from here...
我的虚拟机有可观察的集合,所以不太确定 go 从这里到哪里......
I came up with a simple example我想出了一个简单的例子
1) MVVM helper classes (for visibility): 1) MVVM 辅助类(用于可见性):
public class NotifyPropertyChanged : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
}
2) Markup 2) 标记
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Margin="5">
<Button Content="Add row" Command="{Binding AddRowCommand}"/>
</StackPanel>
<DataGrid ItemsSource="{Binding ItemsList}" Grid.Row="1" AutoGenerateColumns="False" LoadingRow="DataGrid_LoadingRow" CanUserAddRows="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="Column 1" Binding="{Binding Column1}"/>
<DataGridTextColumn Header="Column 2" Binding="{Binding Column2}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
3) ViewModel and data 3) ViewModel 和数据
public class MainViewModel : NotifyPropertyChanged
{
private ObservableCollection<DataItem> _itemsList;
private ICommand _addRowCommand;
public ObservableCollection<DataItem> ItemsList
{
get => _itemsList;
set
{
_itemsList = value;
OnPropertyChanged();
}
}
public ICommand AddRowCommand => _addRowCommand ?? (_addRowCommand = new RelayCommand(parameter =>
{
ItemsList.Add(new DataItem());
}));
public MainViewModel()
{
ItemsList = new ObservableCollection<DataItem>
{
new DataItem { Column1 = "aaa", Column2 = "bbb" },
new DataItem { Column1 = "ccc", Column2 = "ddd" }
};
}
}
public class DataItem : NotifyPropertyChanged
{
private string _column1;
private string _column2;
public string Column1
{
get => _column1;
set
{
_column1 = value;
OnPropertyChanged();
}
}
public string Column2
{
get => _column2;
set
{
_column2 = value;
OnPropertyChanged();
}
}
}
4) And the Event handler in code-behind class 4) 以及代码隐藏 class 中的事件处理程序
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
// condition avoids execution when DataGrid initially loading
// and case when DataGrid adding an empty row if UserCanAddRows is enabled
if (dataGrid.IsLoaded && e.Row.Item is DataItem)
{
dataGrid.Focus(); // moving focus from button to DataGrid
dataGrid.SelectedIndex = e.Row.GetIndex(); // highlighting current row as selected, just a visual thing, you may remove it
dataGrid.CurrentCell = new DataGridCellInfo(e.Row.Item, dataGrid.Columns[0]); // set current cell
Dispatcher.BeginInvoke((Action)(() =>
{
dataGrid.BeginEdit(); // to avoid focus issue I'm running this through Dispatcher asynchronously
}));
}
}
This doesn't break MVVM because Event handler not interacting with data but only check its type.这不会破坏 MVVM,因为事件处理程序不与数据交互而只检查其类型。 Maybe there's a more safe way to check if it's not a
NewItemPlaceholder
in the e.Row.Item
.也许有一种更安全的方法来检查它是否不是
NewItemPlaceholder
中的e.Row.Item
。 Or you may remove type checking in case CanUserAddRows
is set to false.或者,如果
CanUserAddRows
设置为 false,您可以删除类型检查。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.