WPF Keep MouseButtonEvent tunneling down












0















I have a Data Grid, in which I use DragAndDropBehavior to move items up/down :



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


Problem is, that in this DataGrid I have a column with checkbox:



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


So because of this behavior, the checkbox is not responding (when i disable DragAndDrop it works).



I suspect that this is because of my behaviour handles the click event, which is never being tunneled down to my checkbox.



How can I prevent that? I tried setting e.Handled = false somewhere in my behavior, but it didn't work.



P.S Just to be clear I am using my behavior in this way:



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









share|improve this question


















  • 1





    That's a strange approach to DnD, relying on MouseDown is messy. Why not just use MouseMove instead and check if left mouse button is pressed there (e.LeftButton == MouseButtonState.Pressed)?

    – icebat
    Nov 14 '18 at 14:57











  • You are right. And using MouseMove event also solved my issue :). But if I really wanted to use MouseDown event, do you know how to tunnel it down so it would reach my checkbox?

    – Karol Żurowski
    Nov 14 '18 at 16:33
















0















I have a Data Grid, in which I use DragAndDropBehavior to move items up/down :



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


Problem is, that in this DataGrid I have a column with checkbox:



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


So because of this behavior, the checkbox is not responding (when i disable DragAndDrop it works).



I suspect that this is because of my behaviour handles the click event, which is never being tunneled down to my checkbox.



How can I prevent that? I tried setting e.Handled = false somewhere in my behavior, but it didn't work.



P.S Just to be clear I am using my behavior in this way:



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









share|improve this question


















  • 1





    That's a strange approach to DnD, relying on MouseDown is messy. Why not just use MouseMove instead and check if left mouse button is pressed there (e.LeftButton == MouseButtonState.Pressed)?

    – icebat
    Nov 14 '18 at 14:57











  • You are right. And using MouseMove event also solved my issue :). But if I really wanted to use MouseDown event, do you know how to tunnel it down so it would reach my checkbox?

    – Karol Żurowski
    Nov 14 '18 at 16:33














0












0








0








I have a Data Grid, in which I use DragAndDropBehavior to move items up/down :



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


Problem is, that in this DataGrid I have a column with checkbox:



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


So because of this behavior, the checkbox is not responding (when i disable DragAndDrop it works).



I suspect that this is because of my behaviour handles the click event, which is never being tunneled down to my checkbox.



How can I prevent that? I tried setting e.Handled = false somewhere in my behavior, but it didn't work.



P.S Just to be clear I am using my behavior in this way:



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









share|improve this question














I have a Data Grid, in which I use DragAndDropBehavior to move items up/down :



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


Problem is, that in this DataGrid I have a column with checkbox:



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


So because of this behavior, the checkbox is not responding (when i disable DragAndDrop it works).



I suspect that this is because of my behaviour handles the click event, which is never being tunneled down to my checkbox.



How can I prevent that? I tried setting e.Handled = false somewhere in my behavior, but it didn't work.



P.S Just to be clear I am using my behavior in this way:



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






c# wpf xaml






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Nov 14 '18 at 13:27









Karol ŻurowskiKarol Żurowski

170110




170110








  • 1





    That's a strange approach to DnD, relying on MouseDown is messy. Why not just use MouseMove instead and check if left mouse button is pressed there (e.LeftButton == MouseButtonState.Pressed)?

    – icebat
    Nov 14 '18 at 14:57











  • You are right. And using MouseMove event also solved my issue :). But if I really wanted to use MouseDown event, do you know how to tunnel it down so it would reach my checkbox?

    – Karol Żurowski
    Nov 14 '18 at 16:33














  • 1





    That's a strange approach to DnD, relying on MouseDown is messy. Why not just use MouseMove instead and check if left mouse button is pressed there (e.LeftButton == MouseButtonState.Pressed)?

    – icebat
    Nov 14 '18 at 14:57











  • You are right. And using MouseMove event also solved my issue :). But if I really wanted to use MouseDown event, do you know how to tunnel it down so it would reach my checkbox?

    – Karol Żurowski
    Nov 14 '18 at 16:33








1




1





That's a strange approach to DnD, relying on MouseDown is messy. Why not just use MouseMove instead and check if left mouse button is pressed there (e.LeftButton == MouseButtonState.Pressed)?

– icebat
Nov 14 '18 at 14:57





That's a strange approach to DnD, relying on MouseDown is messy. Why not just use MouseMove instead and check if left mouse button is pressed there (e.LeftButton == MouseButtonState.Pressed)?

– icebat
Nov 14 '18 at 14:57













You are right. And using MouseMove event also solved my issue :). But if I really wanted to use MouseDown event, do you know how to tunnel it down so it would reach my checkbox?

– Karol Żurowski
Nov 14 '18 at 16:33





You are right. And using MouseMove event also solved my issue :). But if I really wanted to use MouseDown event, do you know how to tunnel it down so it would reach my checkbox?

– Karol Żurowski
Nov 14 '18 at 16:33












1 Answer
1






active

oldest

votes


















1














A better solution would be to use MouseMove event instead and check if left button is pressed there to start drag and drop: e.LeftButton == MouseButtonState.Pressed.



But if you want a solution using MouseDown like you suggested in comments, then you either need to bubble the event up andor delay the DnD execution because it's the reason the further routing stops.



There are probably some robust solutions already, but from the top of my head we can make it work with simple timer. For that we'll need PreviewMouseLeftButtonUp also:



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


Then we just need to start it with a delay (400 ms here) so that all controls have time to respond. And we stop when mouse button is up:



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


There are ways to make it better but it should work like this.






share|improve this answer


























  • I am not saying, that your answer is wrong, but this is a sort of a "workaround". Do you know how to make this event to be bubbled up?

    – Karol Żurowski
    Nov 16 '18 at 9:03






  • 1





    @KarolŻurowski, you don't need it to bubble up, you can always just use direct handling with AddHandler and not rely on routing stategies and who handles what.

    – icebat
    Nov 16 '18 at 9:38











Your Answer






StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53301343%2fwpf-keep-mousebuttonevent-tunneling-down%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes









1














A better solution would be to use MouseMove event instead and check if left button is pressed there to start drag and drop: e.LeftButton == MouseButtonState.Pressed.



But if you want a solution using MouseDown like you suggested in comments, then you either need to bubble the event up andor delay the DnD execution because it's the reason the further routing stops.



There are probably some robust solutions already, but from the top of my head we can make it work with simple timer. For that we'll need PreviewMouseLeftButtonUp also:



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


Then we just need to start it with a delay (400 ms here) so that all controls have time to respond. And we stop when mouse button is up:



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


There are ways to make it better but it should work like this.






share|improve this answer


























  • I am not saying, that your answer is wrong, but this is a sort of a "workaround". Do you know how to make this event to be bubbled up?

    – Karol Żurowski
    Nov 16 '18 at 9:03






  • 1





    @KarolŻurowski, you don't need it to bubble up, you can always just use direct handling with AddHandler and not rely on routing stategies and who handles what.

    – icebat
    Nov 16 '18 at 9:38
















1














A better solution would be to use MouseMove event instead and check if left button is pressed there to start drag and drop: e.LeftButton == MouseButtonState.Pressed.



But if you want a solution using MouseDown like you suggested in comments, then you either need to bubble the event up andor delay the DnD execution because it's the reason the further routing stops.



There are probably some robust solutions already, but from the top of my head we can make it work with simple timer. For that we'll need PreviewMouseLeftButtonUp also:



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


Then we just need to start it with a delay (400 ms here) so that all controls have time to respond. And we stop when mouse button is up:



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


There are ways to make it better but it should work like this.






share|improve this answer


























  • I am not saying, that your answer is wrong, but this is a sort of a "workaround". Do you know how to make this event to be bubbled up?

    – Karol Żurowski
    Nov 16 '18 at 9:03






  • 1





    @KarolŻurowski, you don't need it to bubble up, you can always just use direct handling with AddHandler and not rely on routing stategies and who handles what.

    – icebat
    Nov 16 '18 at 9:38














1












1








1







A better solution would be to use MouseMove event instead and check if left button is pressed there to start drag and drop: e.LeftButton == MouseButtonState.Pressed.



But if you want a solution using MouseDown like you suggested in comments, then you either need to bubble the event up andor delay the DnD execution because it's the reason the further routing stops.



There are probably some robust solutions already, but from the top of my head we can make it work with simple timer. For that we'll need PreviewMouseLeftButtonUp also:



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


Then we just need to start it with a delay (400 ms here) so that all controls have time to respond. And we stop when mouse button is up:



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


There are ways to make it better but it should work like this.






share|improve this answer















A better solution would be to use MouseMove event instead and check if left button is pressed there to start drag and drop: e.LeftButton == MouseButtonState.Pressed.



But if you want a solution using MouseDown like you suggested in comments, then you either need to bubble the event up andor delay the DnD execution because it's the reason the further routing stops.



There are probably some robust solutions already, but from the top of my head we can make it work with simple timer. For that we'll need PreviewMouseLeftButtonUp also:



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


Then we just need to start it with a delay (400 ms here) so that all controls have time to respond. And we stop when mouse button is up:



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


There are ways to make it better but it should work like this.







share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 15 '18 at 10:57

























answered Nov 15 '18 at 10:51









icebaticebat

4,05531731




4,05531731













  • I am not saying, that your answer is wrong, but this is a sort of a "workaround". Do you know how to make this event to be bubbled up?

    – Karol Żurowski
    Nov 16 '18 at 9:03






  • 1





    @KarolŻurowski, you don't need it to bubble up, you can always just use direct handling with AddHandler and not rely on routing stategies and who handles what.

    – icebat
    Nov 16 '18 at 9:38



















  • I am not saying, that your answer is wrong, but this is a sort of a "workaround". Do you know how to make this event to be bubbled up?

    – Karol Żurowski
    Nov 16 '18 at 9:03






  • 1





    @KarolŻurowski, you don't need it to bubble up, you can always just use direct handling with AddHandler and not rely on routing stategies and who handles what.

    – icebat
    Nov 16 '18 at 9:38

















I am not saying, that your answer is wrong, but this is a sort of a "workaround". Do you know how to make this event to be bubbled up?

– Karol Żurowski
Nov 16 '18 at 9:03





I am not saying, that your answer is wrong, but this is a sort of a "workaround". Do you know how to make this event to be bubbled up?

– Karol Żurowski
Nov 16 '18 at 9:03




1




1





@KarolŻurowski, you don't need it to bubble up, you can always just use direct handling with AddHandler and not rely on routing stategies and who handles what.

– icebat
Nov 16 '18 at 9:38





@KarolŻurowski, you don't need it to bubble up, you can always just use direct handling with AddHandler and not rely on routing stategies and who handles what.

– icebat
Nov 16 '18 at 9:38




















draft saved

draft discarded




















































Thanks for contributing an answer to Stack Overflow!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53301343%2fwpf-keep-mousebuttonevent-tunneling-down%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Xamarin.iOS Cant Deploy on Iphone

Glorious Revolution

Dulmage-Mendelsohn matrix decomposition in Python