Draggable Borderless Window and Button click handler in WPF - c#

The Button handler doesnt work because of the DragMove call in Window mouse down handler. Is there any way how to let the events bubbling? I tried set up e.Handled to false, but it does not work.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
this.DragMove();
e.Handled = false;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
System.Console.WriteLine("zde");
}
}

The Button handler doesnt work because of the DragMove call
Actually, it doesn't work, because the first fires is an event at the Button.Click, and when it works, it conflicts with the events like: MouseLeftButtonDown, MouseUp, MouseDown and for routed events e.Handled property is false by default.
To make this work, you need to define an PreviewMouseDown event, but it's a Tunnel event, this means that it will go down of the VisualTree hierarchy, therefore it is triggered before the Bubble events.
Example:
XAML
<Window x:Class="MyProject.MainWindow"
...
PreviewMouseDown="Window_PreviewMouseDown" ... />
Code-behind
private void Window_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
this.DragMove();
}

Related

UWP: PointerPressed is not fired on a child element

I have an UWP App where a RelativePanel "parent" contains another RelativePanel "child".
Both of them should be able to handle the PointerPressed event, in different ways.
When I click on the parent, the PointerPressed event handler of the parent is correctly fired, but when I click on the child, again only the PointerPressed event handler of the parent is fired, so that the PointerPressed event handler of the child is never invoked.
How can I configure the child so that its PointerPressed event handler is invoked?
Here's an excerpt of the code to create these elements (everything is done in the code behind, since those elements should be created at runtime):
public class ChildView
{
public RelativePanel View { get; set; }
public ChildView()
{
View.Width = 18;
View.Height = 18;
View.SetValue(Canvas.ZIndexProperty, 30); // we want the child always on top of the parent
View.Background = new SolidColorBrush(Colors.Transparent);
// Add the gesture recognizers:
View.Holding += HandleLongPressGesture;
View.PointerPressed += HandleTapGesture;
View.PointerReleased += HandlePointerReleased;
View.DoubleTapped += HandleDoubleTapGesture;
}
public void HandleLongPressGesture(object sender, HoldingRoutedEventArgs e)
{
// my logic
}
private void HandlePointerReleased(object sender, PointerRoutedEventArgs e)
{
// my logic
}
private void HandleDoubleTapGesture(object sender, DoubleTappedRoutedEventArgs e)
{
// my logic
}
private void HandleTapGesture(object sender, PointerRoutedEventArgs e)
{
// my logic
}
}
public class ParentView
{
private ChildView child;
public RelativePanel View { get; set; }
public ParentView()
{
child = new ChildView();
View.Children.Add(child.View);
View.PointerPressed += HandleTapGesture;
View.PointerReleased += HandlePointerReleased;
}
private void HandlePointerReleased(object sender, PointerRoutedEventArgs e)
{
// my logic
}
private void HandleDoubleTapGesture(object sender, DoubleTappedRoutedEventArgs e)
{
// my logic
}
}
set the background of your child panel to transparent.
when the event fires, make sure you do the .Handled=true;
on the incoming handler args to prevent propagation to the parent control.
I'm aware this isn't exactly an answer to your question, but maybe it will help you to debug in some way.
Okay so I set up a simple project (before you added your code to the question) and was unable to replicate your issue.
Basically, the Child click event was getting fired correctly, then the Parent click event was getting fired immediately after, which seems correct to me in this instance.
XAML
<Grid>
<RelativePanel Name="Parent" HorizontalAlignment="Left" Height="460" Margin="437,162,0,0" VerticalAlignment="Top" Width="458" Background="#FFFF5C5C" PointerPressed="Parent_PointerPressed">
<RelativePanel Name="Child" HorizontalAlignment="Left" Height="360" Margin="62,50,0,0" VerticalAlignment="Top" Width="334" Background="#FF3B9C9C" PointerPressed="Child_PointerPressed"/>
</RelativePanel>
</Grid>
C#
private void Parent_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// Breaks here when Parent is pressed
// Also breaks here after breaking on Child_PointerPressed
}
private void Child_PointerPressed(object sender, PointerRoutedEventArgs e)
{
// Breaks here when Child is pressed
}

Event bubbling inside UserControl in C#

I've created a custom UserControl, it's a button with a grid inside it.
From the Page that contains it, MainPage.xaml, I need to bind a Click event to the UserControl, and the function for the EventHandler must be written outside, in the MainPage (not inside the UserControl).
So, reading through this question, I've created an Event and a EventHandler function that triggers the event. These are inside the UserControl.
This are the classes
UserControl.xaml.cs
public class MyButton : UserControl
{
public event RoutedEventHandler ButtonClicked;
private void ButtonClickedHandler()
{
//Null check makes sure the main page is attached to the event
if (this.ButtonClicked != null)
this.ButtonClicked(this, new RoutedEventArgs());
Debug.WriteLine("ButtonClickedHandler");
}
}
MainPage.xaml.cs
private void MyButton_Click(object sender, RoutedEventArgs e)
{
Debug.WriteLine("MyButton_Click");
}
private void MyButton_Loaded(object sender, RoutedEventArgs e)
{
(sender as MyButton).ButtonClicked += MyButton_Click;
}
As you can see, I've placed a couple of Debug.WriteLine, but they don't get triggered, and I don't know what I'm doing wrong.
Just having a single method in your code that is never called by anything will not make your program work. You will first have to call the ButtonClickedHandler() method each time your button is clicked.
To do that, just register a method for the click-event of your button in your xaml file.
<Button Content="This Is Your Button" Click="YourButtonClick"/>
And then call the ButtonClickedHandler() method in there:
private void YourButtonClick(object sender, RoutedEventArgs e) {
ButtonClickedHandler();
}
A simpler way to solve the problem is using an event property:
UserControl.xaml.cs
public Event RoutedEventHandler ButtonClicked
{
add {
ButtonName.Click += value; //use the name of your button here
}
remove {
ButtonName.Click -= value;
}
}
And then you can simply register to that event in your MainWindow:
private void MyButton_Loaded(object sender, RoutedEventArgs e)
{
(sender as MyButton).ButtonClicked += MyButton_Click;
}
By the way, I think it is better to register the event in the xaml file where you also create the control:

routing event to other user control

I need some assistance here.
I have got a button on my window. when button is clicked I want to route the action taken to the event already created in other usercontrol. These usercontrol is embedded in the window itself.
the event in usercontrol is
public void Item_Checked(object sender, RoutedEventArgs e)
{
object selected = this.GetType().GetField("Person", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetValue(this);
this. PropertyGrid1.SelectedObject = selected;
}
button as created in window is as :
<Button Content="clickme" Name="click" Grid.Column="2" Height="20" Width="50" Click="click_Click" />
button event in the window is as shown below:
private void click_Click(object sender, RoutedEventArgs e)
{
/// dosomething
}
can someone help me here please?? I want to call Item_checked event on Button click.
This is a common problem in programming. The generally accepted solution is simply to add a new method containing what is currently in your Item_Checked event handler and then to call that method from the handler and anywhere else you may want to:
In UserControl:
public void DoSomething()
{
object selected = this.GetType().GetField("Person",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Static).GetValue(this);
this.PropertyGrid1.SelectedObject = selected;
}
public void Item_Checked(object sender, RoutedEventArgs e)
{
DoSomething();
}
In Window (where yourUserControl is a reference to your UserControl):
private void click_Click(object sender, RoutedEventArgs e)
{
yourUserControl.DoSomething();
}
Call with null value as RoutedEventArgs as follows
Item_Checked(PropertyGrid1,null);

event not being fired

I have made a custom dialog window that inherits ChildWindow
public partial class InputWindow : ChildWindow
{
public InputWindow()
{
InitializeComponent();
}
private void OKButton_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("clicked");
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
}
private void inputTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
this.OKButton_Click(this, new RoutedEventArgs());
}
}
When I press enter in the tetxbox the event OKButton_Click gets fired ( because message box appears). However, the code (Add Folder) in the event handler below that exists in another class does not get fired! even though the message box appears! Why is this so? and How can I fix it?
InputWindow win = new InputWindow();
win.Title = "Enter New Folder Name";
win.OKButton.Click += (s, e) =>
{
if (!string.IsNullOrWhiteSpace(win.inputTextBox.Text))
{
AddNewFolder(win.inputTextBox.Text);
win.DialogResult = true;
}
};
win.Show();
You're just calling OKButton_click directly from your KeyDown event handler. That's not the same as raising the Click event on the OK button itself - it's just a method call. So it's no wonder that other event handlers for OKButton.Click aren't being called.
I don't know of any way of manually raising the Click event yourself. It sounds like really you should have one common method which is called from both the Click event handler and the KeyDown event handler.

how to set a custom control button's job after adding it to some form?

Im making a userControl named [File_Manager] and i was wondering if i can add a button to this custom control that i can set its job later after adding this custom control to another form .. something like
File_Manager fManager = new File_Manager();
fManager.SetFreeButtonJob( MessageBox.Show("Hello") ); // something like this.
then whenever user press that button .. the messageBox shows up.
So.. Is it possible to do that?
thanks in advance.
Sure you can. Just attach the buttons click handler to the action you pass in.
fManager.SetFreeButtonJob(() => MessageBox.Show("Hello"));
private void SetFreeButtonJob(Action action)
{
button1.Click += (s,e) => action();
}
Just note that passing in the Action breaks the encapsulation of user control though. You should probably do something like SetFreeButtonJob(Jobs.SayHello); and put the knowledge of what to do inside the control.
Create a custom event for your UserControl and fire it when your Button is clicked. You can then attach an event handler to the custom event in your Form. Or you can just raise the UserControl's Click Event when your Button is clicked.
public delegate void CustomClickEventHandler(object sender, EventArgs e);
public partial class buttonTest : UserControl
{
public event CustomClickEventHandler CustomClick;
public buttonTest()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CustomClick(sender, e);
}
}
and in your Form
public Form1()
{
InitializeComponent();
buttonTest1.CustomClick +=new CustomClickEventHandler(userControl1_ButtonClick);
}
private void userControl1_ButtonClick(object sender, EventArgs e)
{
MessageBox.Show("Hello");
}
Or as my second option try.
private void button2_Click(object sender, EventArgs e)
{
OnClick(e);
}
and in your Form subscribe to the UserControl's Click event.
buttonTest1.Click +=new EventHandler(buttonTest1_Click);
private void buttonTest1_Click(object sender, EventArgs e)
{
MessageBox.Show("Hello Again");
}

Categories