C# Passing controls around and maintaining events - c#

Say I have a Form which we'll call it ParentForm, and it contains a Panel which we'll call ContainerPanel. Now, ContainerPanel contains a Panel, which we'll call EntityPanel.
So basically, the Form contains A Panel which contains a Panel.
In ContainerPanel, we have:
void EntityPanel_MouseDown(object sender, MouseEventArgs e)
{
ContainerPanel.Controls.Remove(EntityPanel);
ParentForm.AcceptEntityPanel(EntityPanel);
}
and in MainForm, we have:
void AcceptEntityPanel(Panel panel)
{
Controls.Add(panel);
panel.MouseUp += new MouseEventHandler(
delegate(object sender, MouseEventArgs e)
{
MessageBox.Show("Mouse has been released.");
});
}
Note: This is example code only, which I have just typed in here without verifying syntax, etc. I realise it is trivial to combine these two functions into one, however in my application these two functions do several other things and should be separate.
So the EntityPanel, which belongs to ContainerPanel needs to be transferred to ParentForm when the user presses the mouse down.
When the user releases the mouse, I still need the MouseUp event to be triggered, but it is not working.
Previously, I was passing information about the panel and creating a new panel on the parent form, and manually calling the MouseDown method.
What I'm doing now, as you can see in my above example, is that I'm passing the exact same panel back to the parent form. I had hoped that this way the MouseDown/MouseUp would work, however it didn't.
I'm running out of ideas on how else to structure this module of my program.
Any ideas?

This works for me:
void Form1_Load(object sender, EventArgs e)
{
var innerPanel = new Panel();
outerPanel.Controls.Add(innerPanel);
innerPanel.MouseDown += (a,b) =>
{
outerPanel.Controls.Remove(innerPanel);
Controls.Add(innerPanel);
innerPanel.MouseUp += (x,y) => MessageBox.Show("!");
};
}

Related

Visual Studio Change Panel BackColor on MouseEnter event for mutliple buttons

I'm new to C# and messing around with event Handlers.
I have lots of panels in my form. I want them to change colors if my Mouse ist over them. I can create individual functions in my Form.cs for every panel. Is there a more efficient way? Can you pass a parameter with the event and do something like this and send a the needed Panel as a Parameter?
private void Panel_MouseEnter(object sender, EventArgs e, Panel p)
{
p.BackColor=System.Draw.etc;
}
How would i have to call it from my Form.Designer.cs?
The panel is actually the sender, all you need is Panel p = (Panel)sender;
Because of this, the event can actually be re-used for all of the panels.
This means that you can register all of your panels hover event to the same function.
The full code:
private void Panel_MouseEnter(object sender, EventArgs e)
{
Panel p = (Panel)sender;
p.BackColor=System.Draw.etc;
}
You can write:
private void Panel_MouseEnter(object sender, EventArgs e)
{
var panel = sender as Panel;
if ( panel != null )
panel.BackColor = Color.White;
}
The sender parameter is the control which raises the event.
The as typecasting operator returns null if the instance is of wrong type.
So we check if not null and set the color.
Then all you need is to manually assign this handler to the event of each panel or any control you want.
Or you can automate that for example by putting all desired controls in a panel and writting somewhere, in the form load event handler for example:
// Set for all panels in this panel but not recursively
MyContainerPanel.Controls.OfType<Panel>()
.ToList()
.ForEach(c => c.MouseEnter += Panel_MouseEnter);
// Set for all panels in the form but not recursively
Controls.OfType<Panel>()
.ToList()
.ForEach(c => c.MouseEnter += Panel_MouseEnter);
Also you can filter on the name, a property even the tag:
Controls.OfType<Panel>()
.Where(c => c.Name.StartsWith("panelColorizable"))
.ToList()
.ForEach(c => c.MouseEnter += Panel_MouseEnter);
To assign recursively you can take a look at:
How to toggle visibility in Windows Forms C#
How to format all textbox values on LostFocus event in Winform
Also you can do the same thing on the mouse leav.

The function of buttons is removed when moving to group box?

At the beginning, I had 5 buttons in a panel and they worked perfectly.
For example,
private void btnFlipX_Click(object sender, EventArgs e)
{
imgBox.Image.RotateFlip(RotateFlipType.Rotate180FlipX);
imgBox.Refresh();
}
However, when I moved them to groupbox, they did not work anything. I clicked on a button in groupbox and there was anything in there (there is no code in them). For example,
private void btnFlipX_Click_1(object sender, EventArgs e)
{
}
Anyone can give me the reason of this problem?
It looks like VS just added a new event method for your automatically and named it btnFlipX_Click_1 instead of btnFlipX_Click; Are you sure you are assigning the right event (Where the += is)

Winform DragDrop Event Efficiency

My son and I are working on a hobby project together (Winform app) for the dice game of Farkle and need guidance on handling dragdrop events for the dice. Please note we are not looking for the answer, or the code; just some general ideas on solution attack.
Here are the constructs:
RolledDice
—We have a single form with two panels. One panel contains 6 PictureBoxes which display dice images from an ImageList based on a DiceRoller class we built to generate random integers from 1 to 6. We are using a backing PictureBox array to iterate over each of the PictureBoxes. The click event for a “Roll Dice” button displays the rolled dice—all is good, this works great.
PlayerDice
—The second panel is configured identically to the first one and accepts user selected dice dragged from the Rolled Dice panel. Our use case requires the ability for the user to drag dice from the Rolled Dice panel to the Player Dice panel, and back again if the user changes their mind about the dice they want to keep—all is good, this works great.
Problem Statement
—Although we can drag dice from the Rolled Dice panel to the Player Dice panel (and update the backing PictureBox arrays in the process), it seems necessary to have three event handlers for each of the 6 PictureBoxes in both panels (MouseDown, DragEnter and DragDrop), and this amounts to a ton of code.
Question
—Is there an elegant way to have one set of these 3 event handlers for ALL Rolled Dice and one set of these event handlers for ALL Player Dice, rather than having a bunch of stringy code like we have now?
Again, we are not looking for the exact answer or the code, just some general ideas on solution attack.
EDITED:
Here is the code we have for ONE image.
#region Mouse and Drag Events
// Mouse and Drag Events for ONE Rolled Dice
void pbRolled1_MouseDown(object sender, MouseEventArgs e)
{
PictureBox source = (PictureBox)sender;
DoDragDrop(source.Image, DragDropEffects.Move);
}
void pbRolled1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Bitmap))
e.Effect = DragDropEffects.Move;
}
void pbRolled1_DragDrop(object sender, DragEventArgs e)
{
PictureBox destination = (PictureBox)sender;
destination.Image = (Bitmap)e.Data.GetData(DataFormats.Bitmap);
}
// Mouse and Drag Events for ONE Player Dice
void pbPlayer1_MouseDown(object sender, MouseEventArgs e)
{
PictureBox source = (PictureBox)sender;
DoDragDrop(source.Image, DragDropEffects.Move);
}
void pbPlayer1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(DataFormats.Bitmap))
e.Effect = DragDropEffects.Move;
}
void pbPlayer1_DragDrop(object sender, DragEventArgs e)
{
PictureBox destination = (PictureBox)sender;
destination.Image = (Bitmap)e.Data.GetData(DataFormats.Bitmap);
}
#endregion
You don't necessarily need to have a 1-to-1 relationship between controls and their events - events may be shared between controls.
Since you don't want a specific answer, I'll give you a general example. Take this simple form, with three buttons and a label:
Now, the code for this simple form is as follows (Form1.cs):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.button1.Click += new System.EventHandler(this.button_Click);
this.button2.Click += new System.EventHandler(this.button_Click);
this.button3.Click += new System.EventHandler(this.button_Click);
}
private void button_Click(object sender, EventArgs e)
{
Button button = (sender as Button);
if (button != null)
{
label1.Text = string.Format("You pressed {0}", button.Text);
}
}
}
You could add the events in Design mode, and select the same event for each. I hooked up the events in the constructor just to make it a little more obvious example.
Notice that all three button click handlers point to a single event handler. That handler will look at the sender of the event to see which button was pressed. It then just takes the caption of the button, and displays it in a message in the label.
You can do the similar things with the duplicate events you are creating now (especially after looking at the code you added to your question).
Well the mouse events are handled by the Windows form so that implementation will need to be done on the form but for the drag events you could have your picture boxes implement the IDropTarget interface so that code could be consolidated and give you some reuse and cleaner code.

Is there a way to set a control as a tooltip?

I'm wondering if it's possible to use ToolTip.SetToolTip or something similar to open a control as a tooltip instead of just a string (i.e. SetToolTip(controlToWhichToAdd, panelToDisplayAsToolTip) instead of passing a string as your second parameter).
If this isn't possible I'm guessing next best thing is displaying a panel on the mouse location on mouse_enter event on the control and removing it (or making it invisible) on mouse_leave.
Or are there other practices that make this possible in an easier way?
This is not possible out of the box. You have two choices. First option is to override the Draw Event, which will let you customize how the tooltip looks. Here is an example of this. Be sure you set the OwnerDraw property to true if you use this method!
Although the first method will work if you just need some simple customization, the second option will work best if you need more flexible options. The second option is to do what you already suggested and create your own sort of tooltip. Simply put, you would first create an event handler for the MouseEnter event. When that event fires, you'd enable a Timer. This timer would be the delay that occurs before the tooltip is show. Then finally, you'd just make your panel appear at the mouse coordinates.
Suppose you have a form with a button and timer on it and you want the button to have a tooltip that is a panel:
public partial class Form1 : Form
{
private Panel _myToolTipPanel;
private void Form1_Load(object sender, EventArgs e)
{
_myToolTipPanel = new Panel {Visible = false};
Controls.Add(_myToolTipPanel);
Label myLabel = new Label();
myLabel.Text = "Testing";
_myToolTipPanel.Controls.Add(myLabel);
}
private void button1_MouseEnter(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void button1_MouseLeave(object sender, EventArgs e)
{
timer1.Enabled = false;
_myToolTipPanel.Visible = false;
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
Point position = Cursor.Position;
Point formPoisition = PointToClient(position);
_myToolTipPanel.Visible = true;
_myToolTipPanel.Location = formPoisition;
}
}
Now of course you will have to do some beautifying of the tooltip, but this is the general idea!
One Approach could be inheriting the ToolTip control and then override the SetToolTip and Show methods . Inside the SetToolTip the private method - SetToolTipInternal needs to be re-written , but most of the functionality could be reuse - it uses the Mouse Events ( leave , move) to bind region. but since tooltip uses internal's of windows to show the baloon window. you will have to override quite a bit of code.
but this could be time consuming and needs quite a bit of testing.
You could write a handler for the Tooltip.Popup event, and cancel the popup to display your own panel.
You'd need to clean it up at the appropriate time, though.
For example:
private void ToolTip1_Popup(Object sender, PopupEventArgs e)
{
e.Cancel = true;
//Do work here to display whatever control you'd like
}
If you're just looking for more formatting options in the tooltip display, an alternative is something like this CodeProject entry, which implements an HTML-enabled tooltip:

How to determine which form was brought to front by clicking it?

I have an application with a Panel containing children Form objects. When I click one of the children Form it brings to front. I would like to know which one is in front now...
I've looked in event list but cant find proper event form my purpose :(
These methods doesn't work:
protected void OpenedFileForm_Enter(object sender, EventArgs e)
{
MessageBox.Show("enter");
}
protected void OpenedFileForm_Click(object sender, EventArgs e)
{
MessageBox.Show("click");
}
protected void OpenedFileForm_Activated(object sender, EventArgs e)
{
MessageBox.Show("activated");
}
protected void OpenedFileForm_MouseClick(object sender, MouseEventArgs e)
{
MessageBox.Show("mouse click");
}
protected void OpenedFileForm_Shown(object sender, EventArgs e)
{
MessageBox.Show("shown");
}
OpenFileDialog openFile1 = new OpenFileDialog();
openFile1.DefaultExt = "*.txt";
openFile1.Filter = "TXT Files|*.txt|RTF Files|*.rtf";
if (openFile1.ShowDialog() == System.Windows.Forms.DialogResult.OK &&
openFile1.FileName.Length > 0)
{
switch (Path.GetExtension(openFile1.FileName))
{
case ".txt":
txtForm childTXT = new txtForm();
this.childForms.Add(childTXT);
childTXT.Parent = this.mainPanel;
childTXT.richTextBox1.LoadFile(openFile1.FileName, RichTextBoxStreamType.PlainText);
childTXT.Show();
break;
}
}
Have you tried the Form.Activated Event?
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.activated(v=vs.80).aspx
Edit:
If you are in an MDI application, you might need to use MdiChildActivate instead.
http://msdn.microsoft.com/en-us/library/system.windows.forms.form.mdichildactivate.aspx
This code can only work when you set the Form.TopLevel property to false. Which makes it turn into a child control, almost indistinguishable from a UserControl.
This has many side-effects, for one there is no notion of "front" anymore. The Z-order of child controls is determined by their position in their parent's Controls collection. And it affects the events it fires, Activated and Deactivated will never fire. Furthermore, the Form class was designed to be a container control, it doesn't like taking the focus itself. Its child controls get the focus, the Form class doesn't have any use for focus. Which is why the Enter, Click and MouseClick events don't fire, they are events that require focus.
Long story short, what you are trying to do doesn't make a wholeheckofalot of sense. If it is strictly the Z-order you want to fix then write an event handler for the MouseDown event:
void OpenedFileForm_MouseDown(object sender, MouseEventArgs e) {
var frm = (Form)sender;
frm.BringToFront();
}
You could add frm.Select() to get the Enter event to fire, but only do that if the form doesn't contain any focusable controls itself. Do note that there is evidence that you don't assign the events correctly in your code. The Shown event does fire. It is also important that you set the FormBorderStyle to None, the title bar cannot indicate activation status anymore.
Ok, I got this! Thx for help everyone. You gave me a hint to think about equity of my strange MDI idea where Panel is parent for other Forms. I Removed SplitContainer containing Panel and just did standard MDI application, where Forms are MDIChildren of main Form.
childTXT.MdiParent = this;

Categories

Resources