如果使用拖放,WPF DataGridComboboxColumn selction 将失败

WPF DataGridComboboxColumn selction fails if Drag&Drop is used

我有一个带有 TabControl 的 Usercontrol,包括每个 tabItem 的 Datagrid。 Datagrid 有 3 列,其中一列是组合框列。

<UserControl x:Name="ConfigurationView"
         x:Class="HyperPostHelper.Controls.ConfigurationControl"
         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:viewModel="clr-namespace:HyperPostHelper.ViewModel"
         mc:Ignorable="d"
         d:DesignHeight="300" d:DesignWidth="300"
         ClipToBounds="True"
         HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
         Width="auto" Height="auto"
         Margin="5">
<Grid>
    <TabControl x:Name="ConfigurationTab" ItemsSource="{Binding Path=ConfigurationFiles, UpdateSourceTrigger=PropertyChanged}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock FontWeight="Bold" Text="{Binding FileName, UpdateSourceTrigger=PropertyChanged}" />
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30" />
                        <RowDefinition Height="*" />
                        <RowDefinition Height="30" />
                    </Grid.RowDefinitions>



                    <DataGrid Name="ConfigurationFileView"
                              Grid.Row="1"
                              Margin="2"
                              AutoGenerateColumns="False"
                              ItemsSource="{Binding Parameters,
                                                    UpdateSourceTrigger=PropertyChanged}"
                              SelectedItem="{Binding SelectedItem,
                                                     UpdateSourceTrigger=PropertyChanged}"
                              AllowDrop="True" PreviewMouseLeftButtonDown="ConfigurationFileView_PreviewMouseLeftButtonDown"
                              Drop="ConfigurationFileView_Drop">
                        <DataGrid.RowStyle>
                            <Style TargetType="DataGridRow">
                                <Style.Triggers>
                                    <DataTrigger Binding="{Binding IsValid, UpdateSourceTrigger=PropertyChanged}" Value="true">
                                        <Setter Property="Background" Value="White" />
                                    </DataTrigger>
                                    <DataTrigger Binding="{Binding IsValid, UpdateSourceTrigger=PropertyChanged}" Value="false">
                                        <Setter Property="Background" Value="Red" />
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </DataGrid.RowStyle>
                        <DataGrid.Columns>
                            <DataGridTextColumn Binding="{Binding Name, UpdateSourceTrigger=PropertyChanged}" Header="Name" />
                            <DataGridComboBoxColumn SelectedItemBinding="{Binding Path=Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Header="Type">
                                <DataGridComboBoxColumn.ElementStyle>
                                    <Style TargetType="ComboBox">
                                        <Setter Property="ItemsSource" Value="{Binding ElementName=ConfigurationView, Path=DataContext.Types}" />
                                    </Style>
                                </DataGridComboBoxColumn.ElementStyle>
                                <DataGridComboBoxColumn.EditingElementStyle>
                                    <Style TargetType="ComboBox">
                                        <Setter Property="ItemsSource" Value="{Binding ElementName=ConfigurationView, Path=DataContext.Types}" />
                                    </Style>
                                </DataGridComboBoxColumn.EditingElementStyle>
                            </DataGridComboBoxColumn>
                            <DataGridTextColumn Binding="{Binding Value, UpdateSourceTrigger=PropertyChanged}" Header="Value" Width="*" />
                        </DataGrid.Columns>
                    </DataGrid>
                    <Grid Grid.Row="2">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="30" />
                            <ColumnDefinition Width="30" />
                            <ColumnDefinition Width="auto" />
                        </Grid.ColumnDefinitions>
                        <Button Name="AddParameter"
                                Grid.Row="2" Grid.Column="0"
                                Margin="2"
                                Command="{Binding Path=AddParameterCommand}"
                                Style="{DynamicResource FlatButtonStyle}">
                            <Button.ToolTip>
                                <TextBlock>Adds a new parametert to the selected list</TextBlock>
                            </Button.ToolTip>
                            <Grid>
                                <Image Width="20" Height="20" Source="..\Resources\Property-Add.png" />
                            </Grid>
                        </Button>
                        <!--<Button Name="DeleteParameter" Grid.Row="2" Grid.Column="1" Margin="2" Command="{Binding Path=DeleteParameterCommand}" Style="{DynamicResource FlatButtonStyle}">
                        <Button.ToolTip>
                            <TextBlock>Deletes a selected parameter from the selected list</TextBlock>
                        </Button.ToolTip>
                        <Grid>
                            <Image Width="20" Height="20" Source="..\Resources\Property-Delete.png" />
                        </Grid>
                    </Button>-->
                    </Grid>

                </Grid>
            </DataTemplate>

        </TabControl.ContentTemplate>
    </TabControl>
</Grid>

现在我已经使用 PreviewMouseLeftButtonDown 和 Drop 事件实现了一些用于移动行的拖放功能。这样,拖放就可以正常工作了。但是我不能再使用组合框中的鼠标 select,该框打开并且我可以看到内容,但是如果我想 select 使用鼠标的项目它是 selecting selectedItem 下拉列表下方的数据网格。使用键盘上的 up/down 键,我可以 select.

private void ConfigurationFileView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        DependencyObject source = e.OriginalSource as DependencyObject;
        while (source != null && !(source is System.Windows.Controls.ComboBox))
            source = VisualTreeHelper.GetParent(source);
        if (source != null)
        {
            // don't know what to do here....
        }
        else
        {
            DataGrid dataGrid = (DataGrid)sender;                

            rowIndex = GetCurrentRowIndex(dataGrid, e.GetPosition);
            if (rowIndex < 0)
                return;
            dataGrid.SelectedIndex = rowIndex;
            ParameterVM selectedEmp = dataGrid.Items[rowIndex] as ParameterVM;
            if (selectedEmp == null)
                return;
            DragDropEffects dragdropeffects = DragDropEffects.Move;
            if (DragDrop.DoDragDrop(dataGrid, selectedEmp, dragdropeffects) != DragDropEffects.None)
            {
                dataGrid.SelectedItem = selectedEmp;
            }
        }

    } 

private void ConfigurationFileView_Drop(object sender, DragEventArgs e)
    {
        DataGrid dataGrid = (DataGrid)sender;

        int index = this.GetCurrentRowIndex(dataGrid, e.GetPosition);
        if (index < 0)
            return;

        if (rowIndex < 0)
        {
            ParameterVM newParameter = e.Data.GetData(typeof(ParameterVM))as ParameterVM;
            if (null == newParameter)
                return;

            ObservableCollection<ParameterVM> parameters = dataGrid.ItemsSource as ObservableCollection<ParameterVM>;
            if (!parameters.Any(p => p.Name == newParameter.Name && p.Type == newParameter.Type))
            {
                parameters.Insert(index, newParameter);    
            }                

        }
        else
        {
            if (index == rowIndex)
                return;
            if (index == dataGrid.Items.Count - 1)
            {
                MessageBox.Show("This row-index cannot be drop");
                return;
            }

            ObservableCollection<ParameterVM> parameters = dataGrid.ItemsSource as ObservableCollection<ParameterVM>;
            ParameterVM changedParameter = parameters[rowIndex];
            parameters.Move(rowIndex, index);
        }
    }

我已经在这里阅读了一个答案来检查依赖对象是否是一个组合框。我试过了,但我不知道该怎么做才能通过鼠标 selection 运行 正确。

最后我找到了适合我的解决方案。

我向 DataGrid 添加了两个事件:

BeginningEdit="ConfigurationFileView_BeginningEdit" CellEditEnding="ConfigurationFileView_CellEditEnding"

还在后面添加了一些代码:

public bool IsEditing { get; set; }

    private void ConfigurationFileView_BeginningEdit(object sender, DataGridBeginningEditEventArgs e)
    {
        IsEditing = true;
    }

    private void ConfigurationFileView_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
    {
        IsEditing = false;
    }

并且在 DropEvent 中我添加了一个关于 IsEditing 值的 if:

private void ConfigurationFileView_Drop(object sender, DragEventArgs e)
        {
            if (IsEditing)
                return;

            DataGrid dragSource = e.Data.GetData("DragSource") as DataGrid;
            if (null == dragSource)
                return;

            DataGrid dropTarget = sender as DataGrid;
            if (null == dropTarget)
                return;

            int index = this.GetCurrentRowIndex(dropTarget, e.GetPosition);
            if (index < 0)
                return;            

            .....
        }