Сосредоточиться на заданной c ячейке в строке программно через MVVM, когда наблюдаемая коллекция ItemSource изменяет WPF - PullRequest
0 голосов
/ 01 мая 2020

Я пытаюсь установить фокус на указанной ячейке c в моей DataGrid. Сетка данных связана с наблюдаемой коллекцией X. Когда я нажимаю указанную кнопку c, это приводит к вставке нового X в наблюдаемую коллекцию, но нет никакого акцента на стороне данных сетки данных, и я хочу сосредоточиться курсор, чтобы вы могли ввести новую созданную строку (указанная ячейка c в строке). Возможно ли это по маршруту MVVM? Моя виртуальная машина имеет наблюдаемую коллекцию, поэтому не слишком уверен, откуда go отсюда ...

1 Ответ

0 голосов
/ 02 мая 2020

Я придумал простой пример

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) Разметка

<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 и данные

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) И обработчик событий в классе с выделенным кодом

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

Это не нарушает MVVM, потому что обработчик событий не взаимодействует с данными, а только проверяет их тип. Возможно, есть более безопасный способ проверить, не является ли NewItemPlaceholder в e.Row.Item. Или вы можете отменить проверку типа, если для CanUserAddRows установлено значение false.

DataGrid edit cell on adding row

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...