Arhn - архитектура программирования

Как установить фокус мыши на сведения о строке сетки данных WPF?

Поэтому я использую WPF и шаблон MVVM. У меня есть свойство ItemSource моей сетки данных, привязанное к коллекции объектов домена в моей ViewModel. В сетке данных также определен RowDetailsTemplate, который помогает мне изменять все мои свойства в моем объекте домена. У меня настроена сетка данных, поэтому она позволяет выбирать только одну строку за раз.

Если вам интересно, вот как выглядит мое объявление datagrid:

<DataGrid Name="detailsDataGrid" Grid.Row="1" 
          AutoGenerateColumns="False"
          ItemsSource="{Binding Source={StaticResource Locator}, Path=Details.FileMoverDetails, Mode=OneWay, ValidatesOnDataErrors=True}" 
          SelectedItem="{Binding Source={StaticResource Locator}, Path=Details.SelectedDetail, Mode=TwoWay, ValidatesOnDataErrors=True}" 
          AreRowDetailsFrozen="True" CanUserAddRows="False" CanUserDeleteRows="False" IsReadOnly="True" SelectionMode="Single">

Таким образом, вы также заметите, что SelectedItem также привязан к свойству в моей ViewModel.

Вот моя проблема: под моей сеткой данных у меня есть кнопка «добавить новую запись».

<Button Name="newRecordBtn" DockPanel.Dock="Right" Margin="0,0,10,0" Click="newRecordBtn_Click" >New Record</Button>

который (внутри события щелчка) выполняет мою «AddDetailCommand» в моей ViewModel. «AddDetailCommand» просто создает новый объект домена, добавляет его в коллекцию объектов домена ViewModel, а затем устанавливает свойство ViewModel «SelectedDetail» для вновь созданного объекта. Затем я вызываю RaisePropertyChanged("FileMoverDetails"), за которым следует RaisePropertyChanged("SelectedDetail").

Это заставляет мою сетку данных выбирать вновь созданный элемент и расширять сведения о строке сетки данных. В сведениях о строке моей сетки данных есть много полей, включая поля со списком и текстовые поля. Что подводит меня к моей реальной проблеме: когда я щелкаю левой кнопкой мыши один раз в одном из моих текстовых полей, чтобы начать печатать, фокус не помещается в текстовое поле, и я нужно щелкнуть второй раз, прежде чем я смогу начать печатать. Это происходит с любым элементом управления внутри моих сведений о строке: мне нужно щелкнуть один раз по любому элементу управления, а затем щелкнуть второй раз, прежде чем что-либо произойдет. Эта проблема возникает только в том случае, если я нажимаю кнопку «Добавить новую запись». Это означает, что если я выберу уже существующую строку в сетке данных, то фокус будет правильным, и я могу щелкнуть один раз на любом элементе управления сведениями о строке, и он будет работать так, как ожидалось.

В качестве другого примера проблемы, с которой я сталкиваюсь, у меня есть кнопка «удалить запись» в сведениях о строке сетки данных, которая при активации удаляет текущий выбранный объект домена из коллекции элементов сетки данных. После нажатия кнопки «Добавить новую запись» я иду и сразу же нажимаю один раз кнопку «удалить запись», и ничего не происходит. Но когда я нажимаю второй раз, кнопка работает.

Так что я спрашиваю? После того, как я нажму кнопку "добавить новую запись", я хочу иметь возможность щелкнуть один раз кнопку "удалить запись" и активировать ее функции, не нажимая еще раз .

.

.

Дополнительная информация:

Я думал, что это была чисто проблема с фокусом, поэтому я изменил событие Click кнопки «Добавить новую запись», чтобы установить фокус на один из элементов управления TextBox с данными строки данных после добавления новой записи:

    private void newRecordBtn_Click(object sender, RoutedEventArgs e)
    {
        if (e.Source == newRecordBtn)
        {
            ExecuteNewRecordButtonCommand();
            e.Handled = true;
        }
    }

    private void ExecuteNewRecordButtonCommand()
    {
        if (newRecordBtn.Command.CanExecute(null))
        {
            newRecordBtn.Command.Execute(null);

            if (detailsDataGrid.Items.Count > 0)
            {
                detailsDataGrid.UpdateLayout();

                DataGridRow selectedRow = (DataGridRow)(detailsDataGrid.ItemContainerGenerator.ContainerFromItem(detailsDataGrid.SelectedItem));


                //Get the ContentPresenter of the row details.
                DataGridDetailsPresenter presenter = FindVisualChild<DataGridDetailsPresenter>(selectedRow);

                // Find the localDirectoryText TextBox
                DataTemplate template = presenter.ContentTemplate;

                System.Windows.Controls.TextBox localDirTxt = (System.Windows.Controls.TextBox)template.FindName("localDirectoryText", presenter);

                localDirTxt.Focus();
            }

        }
    }

Угадайте, что случилось? Он установил фокус клавиатуры в TextBox, как я и ожидал (я могу сразу начать печатать, и он поместит мой напечатанный текст в TextBox). Но когда я нажимаю один раз на другом текстовом поле, на кнопке "Удалить запись" или на другом элементе управления (все они находятся в деталях строк сетки данных), ничего не происходит! Затем мне нужно щелкнуть секунду, чтобы элемент управления сделал то, что я ожидал, только один щелчок.

Пожалуйста, помогите, я так старался заставить это работать, и это очень расстраивает. Даже если вы не можете помочь, я хочу поблагодарить вас за то, что вы добрались до этого места в этом описании, я знаю, что оно очень длинное.

Вот мой XAML View (ну, по крайней мере, соответствующие части, я удаляю вещи и помещаю "..." в места, где вещи были удалены):

<Grid>
    <Grid.RowDefinitions>
    ...
    </Grid.RowDefinitions>
    <DataGrid Name="detailsDataGrid" Grid.Row="1" AutoGenerateColumns="False" ItemsSource="{Binding Source={StaticResource Locator}, Path=Details.FileMoverDetails, Mode=OneWay, ValidatesOnDataErrors=True}" SelectedItem="{Binding Source={StaticResource Locator}, Path=Details.SelectedDetail, Mode=TwoWay, ValidatesOnDataErrors=True}" AreRowDetailsFrozen="True" CanUserAddRows="False" CanUserDeleteRows="False" IsReadOnly="True" SelectionMode="Single">
        <DataGrid.Columns>
            ...
            <DataGridTextColumn Header="Local Directory" Binding="{Binding Path=LocalDirectory, ValidatesOnDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Width="175"/>
            <DataGridTextColumn Header="Remote Directory" Binding="{Binding Path=RemoteDirectory, ValidatesOnDataErrors=True, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" Width="175"/>
            ...
        </DataGrid.Columns>
        <DataGrid.RowDetailsTemplate>
            <DataTemplate>
                <Grid Name="rowDetailsGrid" Margin="5,10,0,10" Width="{Binding ElementName=detailsView, Path=ActualWidth}"  HorizontalAlignment="Left" VerticalAlignment="Top" DataContext="{Binding Source={StaticResource Locator}, Path=Details.SelectedDetail}" IsEnabled="{Binding Source={StaticResource Locator}, Path=Details.CanEditDetails, Mode=OneWay}">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="20"/>
                        <ColumnDefinition Width="190"/>
                        <ColumnDefinition Width="20"/>
                        <ColumnDefinition Width="250"/>
                        <ColumnDefinition Width="40"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="30"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <StackPanel Grid.Column="0" Grid.Row="8" Grid.ColumnSpan="3" Orientation="Vertical">
                        ...
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="1*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <TextBox Grid.Column="0" Name="localDirectoryText" Text="{Binding Path=LocalDirectory, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" PreviewKeyDown="localDirectoryText_PreviewKeyDown"/>
                            <Button Grid.Column="1" Width="20" Margin="3,3,0,3" Name="localDirectoryButton" Click="localDirectoryButton_Click">...</Button>
                        </Grid>
                    </StackPanel>
                    <StackPanel Grid.Column="0" Grid.Row="9" Grid.ColumnSpan="3" Orientation="Vertical">
                        ...
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="1*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <TextBox Grid.Column="0" Name="remoteDirectoryText" Text="{Binding Path=RemoteDirectory, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" PreviewKeyDown="remoteDirectoryText_PreviewKeyDown"/>
                            <Button Grid.Column="1" Width="20" Margin="3,3,0,3" Name="remoteDirectoryButton" Click="remoteDirectoryButton_Click">...</Button>
                        </Grid>
                    </StackPanel>
                    ...
                    <DockPanel Grid.Column="4" Grid.Row="10" LastChildFill="False">
                        <Button Name="removeRecordBtn" DockPanel.Dock="Right" Margin="0,15,0,0" Command="{Binding Path=RemoveSelectedDetailCommand}">Remove Record</Button>
                    </DockPanel>
                </Grid>
            </DataTemplate>
        </DataGrid.RowDetailsTemplate>
    </DataGrid>
    <Grid Grid.Row="2" DataContext="{Binding Source={StaticResource Locator}, Path=Details}" IsEnabled="{Binding Path=HasInstance, Mode=OneWay}" Width="{Binding ElementName=detailsView, Path=ActualWidth}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="Auto" MinWidth="125"/>
        </Grid.ColumnDefinitions>
        <DockPanel Grid.Column="1" LastChildFill="False" Margin="0,10,0,7">
            <Button Name="newRecordBtn" DockPanel.Dock="Right" Margin="0,0,10,0" Command="{Binding Path=AddDetailCommand}" Click="newRecordBtn_Click" >New Record</Button>
        </DockPanel>
    </Grid>
</Grid>
14.08.2014

Ответы:


1

После многих вкладок Google Chrome и большого терпения я наконец смог решить свою проблему.

Я не знаю, почему мой предыдущий метод ExecuteNewRecord() не достиг правильного фокуса, но я исправил это следующим образом: сначала передав фокус первой ячейке в текущей выбранной строке, а затем переместив фокус на вторую ячейку. в текущей выбранной строке. Это каким-то образом решило проблему с фокусом.

Вот мои пересмотренные newRecordBtn_Click() и ExecuteNewRecordButtonCommand():

private void newRecordBtn_Click(object sender, RoutedEventArgs e)
{
    if (e.Source == newRecordBtn)
    {
        ExecuteNewRecordButtonCommand();
        e.Handled = true;
    }
}

private void ExecuteNewRecordButtonCommand()
{
    if (newRecordBtn.Command.CanExecute(null))
    {
        newRecordBtn.Command.Execute(null);

        if (detailsDataGrid.Items.Count > 0)
        {
            detailsDataGrid.UpdateLayout();

            DataGridRow selectedRow = 
                (DataGridRow)(detailsDataGrid.ItemContainerGenerator
                                                .ContainerFromItem(detailsDataGrid.SelectedItem));

            DataGridCellsPresenter cellPresenter = FindVisualChild<DataGridCellsPresenter>(selectedRow);

            System.Windows.Controls.DataGridCell firstCell =
                (System.Windows.Controls.DataGridCell)(cellPresenter.ItemContainerGenerator
                                                                    .ContainerFromIndex(0));

            firstCell.Focus();
            firstCell.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
        }
    }
}

Кроме того, если кому-то интересно, что такое метод FindVindVisualChild‹>(), обратите внимание, что я не являюсь первоначальным автором этого метода, и я получил его от http://msdn.microsoft.com/en-us/library/bb613579.aspx.

14.08.2014
Новые материалы

Коллекции публикаций по глубокому обучению
Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

Представляем: Pepita
Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

Советы по коду Laravel #2
1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

3 способа решить квадратное уравнение (3-й мой любимый) -
1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

Создание VR-миров с A-Frame
Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

Демистификация рекурсии
КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..