I am currently working on my first User Control, and are now experiencing some minor problems.
The control is a custom PictureBox with a Button to clear the picture. I am overriding the OnPaint(PaintEventArgs e) method and invalidating the control on MouseEnter and MouseLeave to draw new borders to the control based on mouse state.
This all work as it should. The problem occurs when I want to add a button in the upper right corner (relative to the PictureBox).
1.
The button will not have the correct location relative to the PictureBox. It is placed at the 0th Y-coordinate which is fine, but the X-coordinate is only at position 100, where it should be 160. I am using the User Controls Width property when placing the button, but it seems as it is getting a default value of 100 instead of the 160 that is assigned creating the PictureBox on the form.
CustomPictureBox cpic = new CustomPictureBox();
cpic.Location = new Point(20, 20);
cpic.Height = 80;
cpic.Width = 160;
this.Controls.Add(cpic);
And the button is added like this:
btnClear = new Button();
btnClear.Width = 20;
btnClear.Height = 20;
btnClear.Location = new Point(this.Width - btnClear.Width, 0);
btnClear.Text = "X";
this.Controls.Add(btnClear);
Where does this DefaultValue come from and how can it prevent the control from using it and instead following the width that is specified when initializing a new instance of the control?
2.
Another thing is that I can not get the events for the button to work. I have been googling a lot and tried everything that I can possibly think of, but the events are still not fireing :(
It must be possible to hook on to the buttons MouseClick, MouseEnter and MouseLeave events directly from the User Control?
If you want to see the complete code, you can find it here:
http://pastebin.com/vL14Q5CX
Thanks!
The button is not aligning as expected because:
The button's location is being set in the constructor of the user control
The user control's width is then set in the form
The user control's Resize event is not being handled
In your user control wire up the Resize event and update the location of the button, i.e.:
private void CustomPictureBox1_Resize(object sender, EventArgs e)
{
btnClear.Location = new Point(this.Width - btnClear.Width, 0);
}
The reason the button click events aren't working is because they only bubble up to the parent user control; they will not be received by the form that is hosting the control. You need to create a new custom event handler on your user control that you fire from within the button click event of your user control. You then handle that custom event handler on your form.
HTH
Related
Just wondering if someone else can recreate this or is it just me :)
Drop a panel on the form
Put a button on the panel
Create click of button "I am Button"
Above works fine
Add onmouseleave to panel set button visible to false
Add onmouseenter to panel set button visible to true
Now if you move mouse in and out of panel the button will become visible false. Pefect.
Now move mouse back intp panel and button becomes visible. Perfect.
Clicking on button now does nothing (Lost on Click Event?)
Breakpoint in onclick never fires.
Is this a concept that cannot be done?
'Update' It wont let me post long comment.
First of all thanks for the quick responses.
I did not include code because this was in a very large project so i recreated it with a brand new app.
C# WinForm with one panel and one button on the panel.
I did not try to click on an invible button. Not only can i see the button but can see it respond to bing clicked.
#steve. Good point, The button is well inside of the panel but i see where you are going. I just performed a new test.
If i move the mouse in and out of the panel the button will show and hide perfectly.
After this, hitting enter on the button will excute onclick but the mouse will not. (I suppose this has something to do with only one button and it is default.)
What prompts the mouse to not fire the click event is beyond me.
Very Strange.
What i am trying to achieve:
An area on the screen that when the mouse enters this area a group of buttons appear so they can be used.
when the mouse leaves this area the buttons will dissapear. As my original post stated button works fine if visiblity does not change.
I suppose the your code has the following problem:
You receive the mouseenter event on the panel and you make the button
visible
You move the mouse over the button
This last action triggers the mouseleave event on the panel.
As a consequence your button becomes invisible.
But making the button invisible triggers a mouseenter over the panel and in a blink the button is again visible and causing a mouseleave on the panel.
An infinite loop between these two events starts.
So the click event is not lost, simply it will never trigger because the form engine is busy hiding and showing the button control.
I have reproduced the situation and fixed it adding an event handler for the MouseMove event. In this event I set a variable to block the infinite loop between the two events...
This is my example to adapt to your real code, try it in LinqPad
public class Form1 : Form
{
Button b1 = new Button();
Panel p1 = new Panel();
bool stillOnPanel = false;
public Form1()
{
b1.Text = "ClickMe";
b1.Click += onClick;
b1.Visible = false;
p1.MouseEnter += onEnter;
p1.MouseLeave += onLeave;
p1.MouseMove += onMove;
p1.BorderStyle = BorderStyle.FixedSingle;
p1.Size = new Size(150,100);
this.Controls.Add(p1);
p1.Controls.Add(b1);
}
void onClick(object sender, EventArgs e)
{
Console.WriteLine("Clicked");
}
void onMove(object sender, MouseEventArgs e)
{
//Check if we are still over the panel area
stillOnPanel = b1.ClientRectangle.Contains(p1.PointToClient(Cursor.Position));
}
void onEnter(object sender, EventArgs e)
{
if (!b1.Visible)
{
b1.Visible = true;
}
}
void onLeave(object sender, EventArgs e)
{
// Do not hide the button if we are over it, let it click....
if (b1.Visible && !stillOnPanel)
{
b1.Visible = false;
}
}
}
I have a visual tree that looks like this:
A Border, containing a ScrollViewer, which contains a TexBlock.
The ScrollViewer takes up 100% of the space of the Border, and the TextBlock may or may not take up 100% of the space of the ScrollViewer depending on how the user configures it.
I want to capture a MouseDown event for when a user clicks anywhere in the Border. When I register a MouseDown event for either the Border, or the ScrollViewer, the callback does not get invoked. When I register a MouseDown event to the TextBlock, the callback does get invoked, but of course only in the clickable area of the TextBlock and not the full area of the Border.
One idea that I have is to create some sort of top level element that will go over the whole control, set it's visibility to hidden, then get the MouseDown from that.
Any suggestions? If something is not clear about this question let me know and I will fix it.
Showing Example code per request
// Need to know when a user clicks on anything inside of the border, but the
// because there are items above it, the mouse event doesn't get invoked.
Border border = new Border();
ScrollViewer viewer = new ScrollViewer();
TextBlock textBlock = new TextBlock();
border.Content = viewer;
viewer.Child = textBlock;
You can register PreviewMouseDown event on the Border. It will also fire if a containing element is clicked.
private void Border_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var clickedElement = e.OriginalSource;
}
One more approach (although not that clean IMO) but it could be a useful if you require some custom behavior... maybe :)
We create custom scroll viewer and then use it instead of the standard one, our custom control will just propagate it's mouse down event to it's parent (this example is oversimplified so it's not suitable for use in production in the current state).
public class CustomScrollViewer : ScrollViewer
{
protected override void OnMouseDown(MouseButtonEventArgs e)
{
((e.Source as FrameworkElement).Parent as UIElement).RaiseEvent(e);
}
}
Some info for people like me that weren't familiar with the PreviewMouseDown approach - it's using Routing strategy called Tunneling (from top to bottom) which is the opposite of Bubbling (from bottom to top)
How would I make two buttons appear the same when one is hovered over?
Picture of the buttons I want to be shown are here:
http://i.stack.imgur.com/b4P6B.png
How would I make the button with the green image in the center appear as the same style (colors, borders, etc...) when the Sign On one has been hovered over / clicked?
I'm using Windows Forms.
This can be done using event handlers on mouse over/out, but frankly the right choice is to make a usercontrol containing both buttons and use that instead of the two...
Simply add handler for MouseEnter event on your "sign on" button - all you have to do in this very handler then, is changing second button's styles (implementing MouseLeave might be useful too - to revert second button to it's original style).
Code sample:
this.ButtonSignOn.MouseEnter += this.ChangeOtherButton;
this.ButtonSingOn.MouseLeave += this.RevertOtherButtonChanges;
// later on
private void ChangeOtherButton(object sender, EventArgs e)
{
this.OtherButton.ForeColor = Colors.Red;
this.OtherButton.BackColor = Color.Blue;
// more styling ...
}
// mostly same stuff when reverting changes
You could refactor those 2 handlers into one, and simply passing colors, fonts and other styles as you go... but this should be enough anyways.
I have a Canvas which is present in a UserControl, I have attached the DoubleClick event to this UserControl like this
mainWindow.CanvasLayout.MouseDoubleClick +=
new MouseButtonEventHandler(CanvasLayout_MouseDoubleClick);
I am using this event handler to achieve full screen functionality.
Now, Canvas can have various controls placed inside it. Drag and drop functionality is implemented for these controls similar to this codeproject article.
Basically, I handle these events for a control -
this._dragSource.PreviewMouseLeftButtonDown +=
new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonDown);
this._dragSource.PreviewMouseMove +=
new System.Windows.Input.MouseEventHandler(DragSource_PreviewMouseMove);
this._dragSource.PreviewMouseLeftButtonUp +=
new MouseButtonEventHandler(DragSource_PreviewMouseLeftButtonUp);
Now, when user DoubleClicks on a control(present in canvas) both DoubleClick(Full Screen) and single Click(drag & drop) operations are performed, i.e. if user double clicks on control and change its mouse position quickly, control position is changed(its dragged and dropped to new position).
Is there any way I can prevent drag and drop operation when user double clicks on a control?
Got it, Instead of handling MouseDoubleClick event, I used PreviewMouseLeftButtonDown -
mainWindow.CanvasLayout.PreviewMouseLeftButtonDown
+= new MouseButtonEventHandler(CanvasLayout_PreviewMouseLeftButtonDown);
and
void CanvasLayout_PreviewMouseLeftButtonDown(object s, MouseButtonEventArgs e)
{
if (e.ClickCount > 1)
{
// Do double-click code
// Code for FullScreen
e.Handled = true;
}
}
What you need to do is, on mouse up start a timer the time should be retrieved from SystemInformation.DoubleClickTime, and do the click action on the timer tick (only if you didn't detect the double click in the mean time, obviously).
Likewise use SystemInformation.DragSize to prevent accidental drag&drop.
Note, the SystemInformation class is part of WinForms so you need to add a reference to System.Windows.Forms, this class will work just fine in WPF apps.
I want to add a control to a user control in an event handler (like a button click event).
I'm trying to add a datagridview lookup control dynamically, but I couldn't get that to work, so I tried just adding a button with this code:
private void btnCreateNewButton_Click(object sender, EventArgs e)
{
Button btn = new Button();
btn.Location = new Point(100, 640);
btn.Size = new Size(100, 30);
btn.Text = "Click Me";
btn.Click += (s, ea) => MessageBox.Show("New button clicked");
this.Controls.Add(btn);
}
When i click my Create New Button, no button appears.
If I add the exact same code into a form instead of a usercontrol, the button is created and displays as intended, but in a user control nothing happens.
In the user control I've also tried
this.Parent.Controls.Add(btn) and
this.ParentForm.Controls.Add(btn)
but to no avail.
Anybody got any ideas?
Thanks,
Ciaran.
You place your button on 100,640 point. Please ensure that your user control can accomodate your dynamic button. Otherwise, you won't see it.
I used your code and it worked fine for me, just ensure the proper size of both parent form and user control.
Most likely it is just that your button is being placed out of the bounds of the parent control and/or behind another control. I don't believe that UserControls or Forms are special in respect to adding controls at run-time, but a simple difference may be that Forms are by default re-sizable whereas UserControls aren't? Either way I don't think either Control type will automatically resize to fit all their child controls, so it's quite easy to put a new/dynamic control in the wrong place and have it not be visible.