c# - 如何将鼠标焦点设置到 WPF 数据网格的行详细信息?

标签 c# wpf datagrid rowdetails

所以我使用 WPF 和 MVVM 模式。我将数据网格的 ItemSource 属性绑定(bind)到 ViewModel 中的域对象集合。数据网格还定义了 RowDetailsTemplate,它可以帮助我修改域对象上的所有属性。我设置了数据网格,因此它一次只允许选择一行。

如果您想知道我的数据网格声明是什么样的:

<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 也绑定(bind)到我的 ViewModel 中的属性

这是我的问题:在我的数据网格下方,我有一个“添加新记录”按钮

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

(在单击事件内)在我的 ViewModel 中执行我的“AddDetailCommand”。 “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();
            }

        }
    }

猜猜发生了什么?它将键盘焦点设置到文本框中,就像我预期的那样(我可以立即开始键入,它会将我键入的文本放入文本框中)。但是,当我在不同的文本框或“删除记录”按钮或不同的控件(所有这些都在数据网格的行详细信息中)上单击一次时,什么也没有发生!然后,我必须单击第二次次,控件才能完成我期望只需单击一次即可完成的操作。

请帮忙,我已经尽力让它工作,但非常令人沮丧。即使您无能为力,我也要感谢您在本说明中讲到这里,我知道它很长。

这是我的 View 的 XAML(至少是相关部分,我删除了一些内容并在删除内容的地方放置了“...”):

<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>

最佳答案

经过多次 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 获得它的。 .

关于c# - 如何将鼠标焦点设置到 WPF 数据网格的行详细信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25311183/

相关文章:

c# - 使用 Linq asp.net c# 在 InsertOnSubmit() 的两个不同表中插入数据

wpf - 当该列进入编辑模式时,有没有办法更改 DataGridTextColumn 的绑定(bind)?

c# - 按日期排序 ListView

c# - 数据网格排序 GB、MB、KB、B

C# 为什么这个循环这么慢?

c# - 将 C# void* 转换为 byte[]

c# - 分布式领导者选举算法的可视化模拟器

c# - 在 WPF 中绘制圆圈

apache-flex - 我可以在 flex Graphics 对象上设置文本吗?

c# - LinkBut​​ton 触发 OnClick 事件和 Javascript 事件