I have a ToggleButton
that I have set the template to a new ControlTemplate
I have a behavior that I have added to this ToggleButton
.
<ControlTemplate TargetType="ToggleButton" x:Key="IconToggleButton">
<Border
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="15 0 0 15"
Height="{TemplateBinding Height}"
MinHeight="{TemplateBinding MinHeight}"
VerticalAlignment="{TemplateBinding VerticalAlignment}"
Width="{TemplateBinding Width}">
<Grid>
<TextBlock
FontFamily="{TemplateBinding FontFamily}"
Foreground="{StaticResource White}"
HorizontalAlignment="Center"
Text="{TemplateBinding Content}"
VerticalAlignment="Center" />
</Grid>
</Border>
</ControlTemplate>
<ToggleButton
Background="{StaticResource LightGray}"
BorderBrush="{StaticResource LightGray}"
BorderThickness="1"
Content="{x:Static constants:FontAwesomeIcons.Bars}"
FontFamily="{StaticResource FontAwesomeSolid}"
FontSize="19"
HorizontalAlignment="Center"
MinHeight="35"
MouseLeftButtonDown="UIElement_OnMouseDown"
Template="{StaticResource IconToggleButton}"
VerticalAlignment="Top"
Width="38"
x:Name="ToggleButton">
<b:Interaction.Behaviors>
<b:MouseDragElementBehavior ConstrainToParentBounds="True" />
</b:Interaction.Behaviors>
</ToggleButton>
private void UIElement_OnMouseDown(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine(sender.GetType().Name);
e.Handled = false;
}
My issue is that because the ToggleButton
is handling the event The behavior actually never fires.
So, on to my question: How can I get the behavior to catch this MouseLeftButtonDown
Event.
CodePudding user response:
The MouseDragElementBehavior
does handle the bubbling version of the mouse input events. And those events are marked as handled by the Button
as this event is replaced with the Button.Click
event. This means the UIElement.MouseLeftButtonDown
and the UIElement.MouseDown
events are swallowed by the Button. Only the tunneling versions of those events are allowed to traverse.
To enable drag for a Button
, or any control that marks the bubbling mouse events as handled, with the help of the MouseDragElementBehavior
, you must control this behavior manually.
To achieve this, register a handler for the tunneling UIElement.PreviewMouseLeftButtonDown
event:
<ToggleButton PreviewMouseLeftButtonDown="OnDraggableElementLeftButtonDown">
<b:Interaction.Behaviors>
<b:MouseDragElementBehavior ConstrainToParentBounds="True" />
</b:Interaction.Behaviors>
</ToggleButton>
private Point DragStartPosition { get; set; }
private void OnDraggableElementLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var draggableElement = sender as UIElement;
this.DragStartPosition = e.GetPosition(this);
draggableElement.PreviewMouseMove = OnDraggingElementMouseMove;
draggableElement.PreviewMouseLeftButtonUp = OnDraggedElementLeftButtonUp;
}
protected void OnDraggingElementMouseMove(object sender, MouseEventArgs e)
{
var draggingElement = sender as UIElement;
Microsoft.Xaml.Behaviors.Layout.MouseDragElementBehavior dragMoveBehavior = Microsoft.Xaml.Behaviors.Interaction.GetBehaviors(draggingElement)
.OfType<Microsoft.Xaml.Behaviors.Layout.MouseDragElementBehavior>()
.First();
Point initialDraggableElementPosition = draggingElement.TranslatePoint(new Point(0, 0), this);
if (double.IsNaN(dragMoveBehavior.X))
{
dragMoveBehavior.X = initialDraggableElementPosition.X;
}
if (double.IsNaN(dragMoveBehavior.Y))
{
dragMoveBehavior.Y = initialDraggableElementPosition.Y;
}
Point mousePosition = e.GetPosition(this);
dragMoveBehavior.X = mousePosition.X - this.DragStartPosition.X;
dragMoveBehavior.Y = mousePosition.Y - this.DragStartPosition.Y;
this.DragStartPosition = new Point(mousePosition.X, mousePosition.Y);
}
private void OnDraggedElementLeftButtonUp(object sender, MouseButtonEventArgs e)
{
var draggedElement = sender as UIElement;
draggedElement.PreviewMouseMove -= OnDraggingElementMouseMove;
draggedElement.PreviewMouseLeftButtonUp -= OnDraggedElementLeftButtonUp;
}
To add convenience, you probably would like to wrap the MouseDragElementBehavior
into a custom Behavior
or attached behavior. You then use this behavior to enable element drag. This custom behavior will internally delegate the drag operation to the wrapped MouseDragElementBehavior
using the above code.
CodePudding user response:
If correctly understood, then you need a subscription to has handled event. In XAML (by default), you cannot make such a subscription. Need to use Sharp code in Behavior or Code Behind. Example:
public MainWindow()
{
InitializeComponent();
bttn.AddHandler(
UIElement.MouseLeftButtonDownEvent,
(MouseButtonEventHandler)OnMouseLeftButtonDownForHandled,
true); // "True" - for "catching" all events, including handled ones.
}
private void onm ouseLeftButtonDownForHandled(object sender, MouseButtonEventArgs e)
{
Debug.WriteLine($"The \"{e.RoutedEvent}\" happened");
}