質問

I have added a drag and drop function to a datagrid. However, the datagrid has an embedded DataGridComboBoxColumn that the drag/drop function interferes with. This is because the drag/drop handler does not identify the difference between a user dragging and dropping and a user making a selection from the combobox list (so the user can not select an option from the list).

I would like to either disconnect the drag/drop event whilst the combox isDropDownOpen boolean is set to true or discount this action in the drag/drop handler. However, I can't figure out how to do this as I just cant figure out how to identify when the combobox list is expanded.

My datagrid code is as follows (XAML):

<DataGrid x:Name="dgdNoteLimits"
              Grid.Row="1"
              AllowDrop="True" 
              AutoGenerateColumns="False"
              Background="{DynamicResource myPanelColor}" 
              BorderThickness="0"
              CanUserReorderColumns="False"
              CanUserSortColumns="False"
              ColumnHeaderStyle="{StaticResource headerText}"
              CurrentCellChanged="dgdNoteLimits_CurrentCellChanged"
              HeadersVisibility="Column" 
              HorizontalGridLinesBrush="DarkGray" 
              ItemsSource="{Binding TargetPoints}"
              RowBackground="{DynamicResource myBackgroundColor}" 
              VerticalGridLinesBrush="DarkGray">
        <DataGrid.ItemContainerStyle>
                <Style>
                    <Style.Resources>
                        <!-- SelectedItem's background color when focused -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                                         Color="Blue"/>
                        <!-- SelectedItem's background color when NOT focused -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
                                         Color="Blue" />
                    </Style.Resources>
                </Style>
            </DataGrid.ItemContainerStyle>
            <DataGrid.Columns>
            <DataGridComboBoxColumn x:Name = "dgComboBox"
                                    Header = "Paragraph Type"
                                    ItemsSource = "{Binding Source={StaticResource ParaType}}"
                                    SelectedValueBinding = "{Binding Path=ParagraphType, UpdateSourceTrigger=PropertyChanged}"
                                    TextBinding = "{Binding Path=ParagraphType}"
                                    MinWidth = "115"
                                    Width = "Auto">
                <DataGridComboBoxColumn.ElementStyle>
                    <Style TargetType = "ComboBox">
                        <Setter Property = "Foreground"
                                Value = "{DynamicResource TextColor}"/>
                        <EventSetter Event="SelectionChanged"
                                     Handler = "OnDropDownOpenedEvent" />
                    </Style>
                </DataGridComboBoxColumn.ElementStyle>
            </DataGridComboBoxColumn>
            <DataGridTextColumn x:Name="dgdTextColumn"
                                Header="Description"
                                Binding="{Binding Path=ParagraphText, UpdateSourceTrigger=PropertyChanged}"
                                Width="*">
                <DataGridTextColumn.ElementStyle>
                    <Style x:Name="myStyle"
                            TargetType="TextBlock">
                        <Setter Property="SpellCheck.IsEnabled"
                                Value="true" />
                        <Setter Property="TextWrapping"
                                Value="Wrap"/>
                        <Setter Property="Foreground"
                                Value="{DynamicResource myTextColor}"/>
                    </Style>
                </DataGridTextColumn.ElementStyle>
            </DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>

A subset of my code behind is as follows:

private bool IsTheMouseOnTargetRow(Visual theTarget, GetDragDropPosition pos)
{
    if (theTarget != null)
    {
        Rect posBounds = VisualTreeHelper.GetDescendantBounds(theTarget);
        Point theMousePos = pos((IInputElement)theTarget);
        return posBounds.Contains(theMousePos);
    }
    else
        return false;
}

private DataGridRow GetDataGridRowItem(int index)
{
    if (dgdNoteLimits.ItemContainerGenerator.Status != System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
        return null;

    return dgdNoteLimits.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;
}

private int GetDataGridItemCurrentRowIndex(GetDragDropPosition pos)
{
    int curIndex = -1;
    DataGridRow itm;

    for (int i = 0; i < dgdNoteLimits.Items.Count; i++)
    {
        itm = GetDataGridRowItem(i);
        if (IsTheMouseOnTargetRow(itm, pos))
        {
            curIndex = i;
            break;
        }
    }

    return curIndex;
}

void dgdNoteLimits_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    prevRowIndex = GetDataGridItemCurrentRowIndex(e.GetPosition);

    if (prevRowIndex < 0)
        return;

    dgdNoteLimits.SelectedIndex = prevRowIndex;

    INote selectedNote = dgdNoteLimits.Items[prevRowIndex] as INote;

    if (selectedNote == null)
        return;

    if (isDroppedDown)
        return;

    //Now creare a Drop rectangle with Mouse Drag-Effect
    //Here you can select the Effect as per your choice
    DragDropEffects dragDropEffects = DragDropEffects.Move;

    if (DragDrop.DoDragDrop(dgdNoteLimits, selectedNote, dragDropEffects) != DragDropEffects.None)
    { 
        //This Item is dropped at the new datagrid location and so the new selected item
        dgdNoteLimits.SelectedItem = selectedNote;
    }
}

void dgdNoteLimits_Drop(object sender, DragEventArgs e)
{
    if (prevRowIndex < 0)
        return;

    int index = this.GetDataGridItemCurrentRowIndex(e.GetPosition);

    //The current Rowindex is -1 (No selection)
    if (index < 0)
        return;

    //If Drag-Drop Location are same.
    if (index == prevRowIndex)
        return;

    /* NOT REQUIRED AS LAST ROW IS NOT FOR INSERTIONS
    // If the drop index is the last Row of datagrid
    // (Note: This row is typically used for performing insert operations)
    if (index == dgdNoteLimits.Items.Count - 1)
    {
        MessageBox.Show("You cannot use this row-index for drop operations");
        return;
    }*/

    INote movedNote = Paragraphs[prevRowIndex];
    Paragraphs.RemoveAt(prevRowIndex);
    Paragraphs.Insert(index, movedNote);
}

Thanks

役に立ちましたか?

解決

Before you start the drag drop operation you could check to make sure that it's not a combo box with something like this.

    protected override void OnPreviewMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e)
    {
        DependencyObject source = e.OriginalSource as DependencyObject;
        while (source != null && !(source is System.Windows.Controls.ComboBox)) source = VisualTreeHelper.GetParent(source);
        if (source != null)
        {
            // it was a combo box, don't start drag drop.
        }
        else
        {
            // it wasn't a combo box do drag drop.
        }


        base.OnPreviewMouseLeftButtonDown(e);
    }
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top