WPF Keep MouseButtonEvent tunneling down
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
add a comment |
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
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
add a comment |
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
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
c# wpf xaml
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
add a comment |
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
add a comment |
1 Answer
1
active
oldest
votes
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.
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
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
add a comment |
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.
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
add a comment |
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.
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.
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
add a comment |
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
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
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