WPF Keep MouseButtonEvent туннелирование вниз - PullRequest
0 голосов
/ 14 ноября 2018

У меня есть таблица данных, в которой я использую DragAndDropBehavior для перемещения элементов вверх / вниз:

public class DataGridRowDragAndDropBehavior
    {    
        public  delegate  Point GetPosition(IInputElement element);


        int   rowIndex = -1;

        public static DependencyProperty DataGridDragAndDropEnabled =
            DependencyProperty.RegisterAttached("DataGridDragAndDropEnabled", typeof(bool),
                typeof(DataGridRowDragAndDropBehavior), new UIPropertyMetadata(false, OnDataGridDragAndDropEnabled));

        private static void OnDataGridDragAndDropEnabled(object sender, DependencyPropertyChangedEventArgs e)
        {
            var dataGrid = (DataGrid) sender;
          dataGrid.PreviewMouseLeftButtonDown += Instance.productsDataGrid_PreviewMouseLeftButtonDown;
           dataGrid.Drop +=Instance.productsDataGrid_Drop;

        }

        public static bool GetDataGridDragAndDropEnabled(DependencyObject obj)
        {
            return (bool) obj.GetValue(DataGridDragAndDropEnabled);
        }
        public static void SetDataGridDragAndDropEnabled(DependencyObject obj, bool value)
        {
            obj.SetValue(DataGridDragAndDropEnabled, value);
        }


        private static DataGridRowDragAndDropBehavior instance = new DataGridRowDragAndDropBehavior();

        public static DataGridRowDragAndDropBehavior Instance
        {
            get { return instance; }
            set { instance = value; }
        }

         void productsDataGrid_Drop(object sender, DragEventArgs e)
         {

             var dataGrid = (DataGrid) sender;
             var dataGridSource = (System.Collections.IList)dataGrid.ItemsSource;

            if (rowIndex < 0)
                    return;
                var index = GetCurrentRowIndex(e.GetPosition,dataGrid);
                if (index < 0)
                    return;
                if (index == rowIndex)
                    return;
                //if (index == dataGrid.Items.Count - 1)
                //{
                //    MessageBox.Show("This row-index cannot be drop");
                //    return;
                //}

                var  changedItem = dataGridSource[rowIndex];
                dataGridSource.RemoveAt(rowIndex);
                dataGridSource.Insert(index, changedItem);


         }

         void   productsDataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
         {

             var dataGrid = (DataGrid) sender;

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


         }

        private  bool GetMouseTargetRow(Visual theTarget, GetPosition position)
        {
            Rect rect = VisualTreeHelper.GetDescendantBounds(theTarget);
            Point point = position((IInputElement)theTarget);
            return rect.Contains(point);
        }

        private  DataGridRow GetRowItem(int index,DataGrid dataGrid)
        {
            if (dataGrid.ItemContainerGenerator.Status
                    != GeneratorStatus.ContainersGenerated)
                return null;
            return dataGrid.ItemContainerGenerator.ContainerFromIndex(index)
                                                            as DataGridRow;
        }

        private   int GetCurrentRowIndex(GetPosition pos,DataGrid dataGrid)
        {
            int curIndex = -1;
            for (int i = 0; i < dataGrid.Items.Count; i++)
            {
                DataGridRow itm = GetRowItem(i,dataGrid);
                if (GetMouseTargetRow(itm, pos))
                {
                    curIndex = i;
                    break;
                }
            }
            return curIndex;
        }
    }

Проблема в том, что в этой DataGrid у меня есть столбец с флажком:

<DataGridTemplateColumn Header="CheckBox Column" IsReadOnly="False">
  <DataGridTemplateColumn.CellTemplate>
    <DataTemplate>                                   
       <CheckBox>My checkbox</CheckBox>
    </DataTemplate>                          
  </DataGridTemplateColumn.CellTemplate> 
</DataGridTemplateColumn>

Поэтому из-за этого поведения флажок не отвечает (когда я отключаю DragAndDrop, он работает).

Я подозреваю, что это из-за того, что мое поведение обрабатывает событие click, которое никогда не передается на мой флажок.

Как я могу предотвратить это? Я пытался установить e.Handled = false где-то в своем поведении, но это не сработало.

P.S Просто для ясности, я использую свое поведение таким образом:

 <DataGrid behaviors:DataGridRowDragAndDropBehavior.DataGridDragAndDropEnabled="true">

1 Ответ

0 голосов
/ 15 ноября 2018

Лучшим решением было бы использовать событие MouseMove и проверить, нажата ли там левая кнопка, чтобы начать перетаскивание: e.LeftButton == MouseButtonState.Pressed.

Но если вы хотите решение, использующее MouseDown, напримерВы предложили в комментариях, тогда вам нужно либо всплыть событие и \ или задержать выполнение DnD, потому что это причина, по которой дальнейшая маршрутизация останавливается.

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

private static void OnDataGridDragAndDropEnabled(object sender, DependencyPropertyChangedEventArgs e)
{
    var dataGrid = (DataGrid)sender;
    dataGrid.PreviewMouseLeftButtonDown += Instance.productsDataGrid_PreviewMouseLeftButtonDown;
    dataGrid.PreviewMouseLeftButtonUp += Instance.productsDataGrid_PreviewMouseLeftButtonUp;
    dataGrid.Drop += Instance.productsDataGrid_Drop;
}

Тогда нам просто нужно запустить его с задержкой (здесь 400 мс), чтобы все элементы управления успели ответить.И мы останавливаемся, когда кнопка мыши нажата:

private System.Timers.Timer dragTimer;

void productsDataGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
   var dataGrid = (DataGrid)sender;

   dragTimer = new System.Timers.Timer(400);
   System.Timers.ElapsedEventHandler elapsed = null;
   elapsed = (s, ee) =>
   {
      dragTimer.Elapsed -= elapsed;

      dataGrid.Dispatcher.Invoke(() =>
      {
         rowIndex = GetCurrentRowIndex(e.GetPosition, dataGrid);
         if (rowIndex < 0) return;

         dataGrid.SelectedIndex = rowIndex;
         object selectedEmp = dataGrid.Items[rowIndex];
         if (selectedEmp == null) return;

         DragDropEffects dragdropeffects = DragDropEffects.Move;
         if (DragDrop.DoDragDrop(dataGrid, selectedEmp, dragdropeffects)
               != DragDropEffects.None)
         {
            dataGrid.SelectedItem = selectedEmp;
         }
      });
   };

   dragTimer.Elapsed += elapsed;
   dragTimer.Start();
}

private void productsDataGrid_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
   if (dragTimer == null) return;

   dragTimer.Stop();
   dragTimer.Dispose();
   dragTimer = null;
}

Есть способы сделать ее лучше, но она должна работать следующим образом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...