gong-wpf-dragdrop icon indicating copy to clipboard operation
gong-wpf-dragdrop copied to clipboard

Drag and drop behavior on DataGrid looks strange

Open CodingOctocat opened this issue 8 months ago • 1 comments

Describe the bug

  1. Drag and drop only in certain positions
  2. When dragging and dropping, the position indicator flashes to the end when the mouse pointer is in the item gap

To Reproduce Steps to reproduce the behavior:

<DataGrid d:ItemsSource="{d:SampleData ItemCount=5}"
          dd:DragDrop.CanDragWithMouseRightButton="False"
          dd:DragDrop.IsDragSource="True"
          dd:DragDrop.IsDropTarget="True"
          dd:DragDrop.SelectDroppedItems="True"
          dd:DragDrop.UseDefaultDragAdorner="True"
          hc:Empty.ShowEmpty="True"
          hc:WindowAttach.IsDragElement="False"
          AlternationCount="{Binding Items.Count, RelativeSource={RelativeSource Self}}"
          AutoGenerateColumns="False"
          CanUserReorderColumns="False"
          CanUserResizeColumns="False"
          CanUserResizeRows="False"
          CanUserSortColumns="False"
          ItemsSource="{Binding FireTableColumnMap.SkipRowRules}"
          RowHeight="{StaticResource NaN}"
          SelectionMode="Single"
          SelectionUnit="FullRow">
    <DataGrid.RowStyle>
        <Style BasedOn="{StaticResource DataGridRowStyle}"
               TargetType="{x:Type DataGridRow}">
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="{DynamicResource RegionBrush}" />

                </Trigger>

                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="{DynamicResource LightPrimaryBrush}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.RowStyle>

    <DataGrid.CellStyle>
        <Style BasedOn="{StaticResource DataGridCellStyle}"
               TargetType="{x:Type DataGridCell}">
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="Transparent" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </DataGrid.CellStyle>

    <DataGrid.Columns>
        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <hc:SimpleStackPanel Orientation="Horizontal">
                        <Button hc:IconElement.Geometry="{StaticResource AlignHStretchGeometry}"
                                Foreground="{DynamicResource MyReverseBrush}"
                                Opacity="0.5"
                                Style="{StaticResource ButtonIcon}"
                                ToolTip="🟠 My final thought is to drag and drop this icon to sort row item" />

                        <TextBlock VerticalAlignment="Center"
                                   Foreground="{DynamicResource MyReverseBrush}"
                                   Text="{Binding AlternationIndex, RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={StaticResource AddOneConverter}, Mode=OneWay}" />
                    </hc:SimpleStackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn>
            <DataGridTemplateColumn.Header>
                <TextBlock Text="启用" />
            </DataGridTemplateColumn.Header>

            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate DataType="{x:Type m:FireTableSkipRowRule}">
                    <CheckBox HorizontalAlignment="Center"
                              IsChecked="{Binding IsEnabled}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn Header="目标列">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate DataType="{x:Type m:FireTableSkipRowRule}">
                    <ComboBox DisplayMemberPath="Display"
                              ItemsSource="{Binding Data.FireTableRequiredColumnNumbers, Source={StaticResource DataContextProxy}}"
                              SelectedValue="{Binding TargetColumn, Converter={StaticResource EnumToIntConverter}}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn MinWidth="100"
                                MaxWidth="278"
                                Header="匹配文本">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate DataType="{x:Type m:FireTableSkipRowRule}">
                    <TextBox Padding="8"
                             Text="{Binding MatchText}"
                             TextWrapping="Wrap" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn>
            <DataGridTemplateColumn.Header>
                <TextBlock Text="  区分&#x0A;大小写" />
            </DataGridTemplateColumn.Header>

            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate DataType="{x:Type m:FireTableSkipRowRule}">
                    <CheckBox HorizontalAlignment="Center"
                              IsChecked="{Binding IsMatchCase}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn>
            <DataGridTemplateColumn.Header>
                <TextBlock Text="全字&#x0A;匹配" />
            </DataGridTemplateColumn.Header>

            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate DataType="{x:Type m:FireTableSkipRowRule}">
                    <CheckBox HorizontalAlignment="Center"
                              IsChecked="{Binding IsMatchWholeWord}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>

        <DataGridTemplateColumn>
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Button hc:IconElement.Geometry="{StaticResource DeleteGeometry}"
                            Command="{Binding Data.DeleteSkipRowRuleCommand, Source={StaticResource DataContextProxy}}"
                            CommandParameter="{Binding}"
                            Foreground="{DynamicResource DangerBrush}"
                            Style="{StaticResource ButtonIcon}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Expected behavior

  1. Only the icons in the first column are allowed to be dragged and dropped for sorting
  2. When dragging and dropping, the indicator should not flash to the end when the mouse pointer is in the row gap

Screenshots

Image

Desktop (please complete the following information):

  • OS: [Win11 24h2 26100.3194]
  • gong-wpf-dragdrop [4.0.0]

CodingOctocat avatar Mar 15 '25 04:03 CodingOctocat

I solved the problem, however, I think it's rather inconvenient.

<DataGrid dd:DragDrop.IsDragSource="False" // Set False!!!
          dd:DragDrop.DropHandler="{Binding}"
    ...
<DataGridTemplateColumn>
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <hc:SimpleStackPanel Orientation="Horizontal">
                <Button dd:DragDrop.IsDragSource="True" // Set True here
                        hc:IconElement.Geometry="{StaticResource AlignHStretchGeometry}"
                        Foreground="{DynamicResource MyReverseBrush}"
                        Opacity="0.5"
                        Style="{StaticResource ButtonIcon}"
                        ToolTip="Drag/Drop to reorder" />

                <TextBlock VerticalAlignment="Center"
                           Foreground="{DynamicResource MyReverseBrush}"
                           Text="{Binding AlternationIndex, RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={StaticResource AddOneConverter}, Mode=OneWay}" />
            </hc:SimpleStackPanel>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>

Just having the above code would cause the COPY effect for each drag and drop, so I had to handle the drag/drop event manually.Then the problem was solved, the only downside was that I lost the thumbnail effect on DragOver, UseDefaultDragAdorner="True" was disabled.

public void DragOver(IDropInfo dropInfo)
{
    if (dropInfo.Data is FireTableSkipRowRule && dropInfo.TargetItem is FireTableSkipRowRule)
    {
        dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
        dropInfo.Effects = DragDropEffects.Move;
    }
}

public void Drop(IDropInfo dropInfo)
{
    if (dropInfo.Data is FireTableSkipRowRule sourceItem)
    {
        int oldIndex = SkipRowRules.IndexOf(sourceItem);

        if (oldIndex == dropInfo.InsertIndex)
        {
            return;
        }

        int newIndex = dropInfo.InsertIndex > oldIndex ? dropInfo.InsertIndex - 1 : dropInfo.InsertIndex;

        SkipRowRules.Move(oldIndex, newIndex);
    }
}

As for the drop indicator jumping, I don't know why, but I haven't encountered it after using the above solution.

I suggest gong-wpf-dragdrop to improve this issue, it is a common requirement to allow drag and drop only for the specified button position, and the MOVE effect should be maintained when it is set as the drag and drop source.

CodingOctocat avatar Mar 15 '25 09:03 CodingOctocat