I have some Panel's and each Panel has a PictureBox and a Label in it.
public static void redPanel(Panel panel1)
{
panel1.MouseEnter += new EventHandler((o, a) => panel1.BackColor = Color.Brown);
panel1.MouseDown += new MouseEventHandler((o, a) => panel1.BackColor = Color.DarkRed);
panel1.MouseUp += new MouseEventHandler((o, a) => panel1.BackColor = Color.Firebrick);
panel1.MouseLeave += new EventHandler((o, a) => panel1.BackColor = Color.Firebrick);
}
I made this code so the panel reacts to mouse hover and click ... but if I hover the Label or the PictureBox the Panel reverts to its original color. I want that the Label and the PictureBox to act exactly like the Panel (ex: If I click the Label I want that to count as a click on the Panel).
I want some code ... like SourceControl or something for the function from top to manage its own Label and PicureBox.
P.S: I tried to make another functions for Label and PictureBox but each Panel has different color so It means that I need to have about 23 lines of code just for labels ...
Quick answer: just attach the same handler to all of them.
public static void redPanel(Panel panel1)
{
var mouseEnter = new EventHandler((o, a) => panel1.BackColor = Color.Brown);
panel1.MouseEnter += mouseEnter;
pictureBox1.MouseEnter += mouseEnter;
label1.MouseEnter += mouseEnter;
// And so on
}
Better answer: change your code, if it's a reusable component you'd better to create a UserControl with a PictureBox and a Label. From Designer then assign the same event handler to events generated from both of them (plus UserControl itself).
That said a button is much more than that (it has to react to keyboard events, can be focused, can be default button and so on). I'd prefer to derive from button to just add drawing features (a label and an image are very little code).
Related
I made a simple button, but when i click outside of win form my button getting a black border. By the way i set BorderSize to "0" and it works great while i clicking inside of my form.
this.button.FlatAppearance.BorderSize = 0;
That's how it looks like.
it seems a focus problem. Try to reset the focus when the cursor leave the control.
Add these lines of code to your forms load event.
btn.FlatStyle = FlatStyle.Flat;//You can also use the popup flat style
btn.FlatAppearance.BorderColor = btn.Parent.BackColor;
btn.FlatAppearance.BorderSize = 0;
One simple workaround is to set the FlatAppearance.BorderColor of the Button to its Parent.BackColor:
this.button1.FlatAppearance.BorderColor = this.button1.Parent.BackColor;
You could set this Property subscribing to the ParentChanged event (or overriding OnParentChanged, if it's a Custom Control) if the Control can be assigned to another parent at some point.
You can also perform the same operation in batch, using the HandleCreated event and have all the Buttons (with FlatStyle = FlatStyle.Flat) subscribe to the event in the Form's constructor:
public Form1()
{
InitializeComponent();
foreach (Button button in this.Controls.OfType<Button>().Where(btn => btn.FlatStyle == FlatStyle.Flat))
{
button.HandleCreated += (s, e) => {
button.FlatAppearance.BorderColor = button.Parent.BackColor;
};
}
}
I have a Canvas (not InkCanvas) inside a Scrollviewer. Both are not created in XAML but in code behind. I want to draw lines on my Canvas with Pen and Mouse input, everything works just fine but now I tested the whole thing with a pen as input device and the Scrollviewer seems to recognize it as touch input because the whole thing starts scrolling.
My question is: Is it possible to tell the Scrollviewer to ignore all inputs from a device type? Because it also seems like the Scrollviewer is 'eating' the events which should be fired from the Canvas.
Here my Scrollviewer init:
private void SetUpScrollViewer()
{
scroll = new ScrollViewer();
scroll.VerticalScrollMode = ScrollMode.Auto;
scroll.HorizontalScrollMode = ScrollMode.Auto;
scroll.VerticalScrollBarVisibility = ScrollBarVisibility.Visible;
scroll.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
scroll.ZoomMode = ZoomMode.Enabled;
scroll.ManipulationMode = ManipulationModes.System;
scroll.HorizontalAlignment = HorizontalAlignment.Left;
scroll.VerticalAlignment = VerticalAlignment.Top;
scroll.IsZoomInertiaEnabled = false;
scroll.MinZoomFactor = 1;
scroll.MaxZoomFactor = 5;
}
Those are the events I use in my Canvas:
public void EnableDrawingOnCanvas(Canvas canvas)
{
//Adding the needed event handler.
canvas.PointerPressed += Canvas_PointerPressed;
canvas.PointerMoved += Canvas_PointerMoved;
canvas.PointerReleased += Canvas_PointerReleased;
canvas.PointerExited += Canvas_PointerExited;
}
And those events all check if the input device is everything but touch like this
if (e.Pointer.PointerDeviceType != Windows.Devices.Input.PointerDeviceType.Touch){...}
But with those Events I can only check the input device for my Canvas and if I add a Event to the Scrollviewer it won't get passed to the Canvas afaik.
You can bind a PointerPressed event to your ScrollViewer and check if the e.Pointer.PointerDeviceType equals PointerDeviceType.Pen. Then you can disable the VerticalScrollMode the HorizontalScrollMode and the ZoomMode like in the code below.
If you want to reactivate the ScrollViewer you can bind a PointerExited event to your ScrollViewer and reenable everything.
private void Scroll_PointerPressed(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == PointerDeviceType.Pen)
{
scroll.VerticalScrollMode = ScrollMode.Disabled;
scroll.HorizontalScrollMode = ScrollMode.Disabled;
scroll.ZoomMode = ZoomMode.Disabled;
}
}
In my application I dynamically create buttons and add them to a flow control that is later cleared. I have this on a timer to refresh every X seconds to clear then add buttons. This is all being done on the main form.
The problem is when I have a child form launched the main form will steal focus every time the controls are added to the flow control.
Here is the code I have that dynamically clears and adds the controls on the main form.
I call this before adding the controls
flw_users.Controls.Clear();
This is what I call to dynamically create/add the buttons to the flow control.
private void DisplayNewMobileUser(string MobileUserName)
{
// Set Button properties
Button button = new Button();
button.Text = MobileUserName;
button.Size = new System.Drawing.Size(171, 28);
button.Name = MobileUserName;
button.BackColor = System.Drawing.Color.White;
button.FlatAppearance.BorderColor = System.Drawing.Color.White;
button.Font = new System.Drawing.Font("Segoe UI", 12F, System.Drawing.FontStyle.Bold);
button.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
button.ForeColor = System.Drawing.Color.Black;
button.Margin = new System.Windows.Forms.Padding(0, 1, 0, 1);
button.TextAlign = System.Drawing.ContentAlignment.TopLeft;
button.Click += new EventHandler(MobileUserName_OnClick);
flw_users.Controls.Add(button);
}
Is there a way to add buttons to a flow control with out it always stealing focus ?
Thanks to LarsTech I researched how to properly dispose each control added to flw_users. The main issues was fixed by changing the OnClick event to change focus to a label, which in turn didn't cause the main form to gain topmost every time the controls were cleared and re added. So everytime I clicked a button that button still had focus while the new form appeared.
Thanks everyone !
Here is the code I used to properly clear the controls
private void ClearUsers()
{
List<Control> ctrls = new List<Control>();
foreach (Control c in flw_users.Controls)
{
ctrls.Add(c);
}
flw_users.Controls.Clear();
foreach (Control c in ctrls)
{
c.Dispose();
}
}
For my C# Windows Form Application, I have created a flowlayoutpanel that contains several panels. Inside the panel, I have a button "Clear" for each and every single panel.
How do I write the event handler for the code for the button "Clear" such that once I have click the button, the panel would sort of be "Removed" from the flowlayoutpanel.
This is a short part of the code of the adding of panels to the flowlayoutpanel.
nFlowPanel.Controls.Add(createNotificationPanel());
nFlowPanel.Controls.Add(createNotificationPanel());
nFlowPanel.Controls.Add(createNotificationPanel());
nFlowPanel.Controls.Add(createNotificationPanelImpt());
nFlowPanel.Controls.Add(createNotificationPanelImpt());
and this is the code for the button "Clear"
Button btnClear = new Button
{
Text = "Clear",
Name = "btnClear",
Location = new Point(416, 17)
};
p.Controls.Add(btnClear);
btnClear.Click += new EventHandler(buttonClear_Click);
So what should i write in the following method to have the effect of removing e.g. the second panel that was added in the first part of code I have written?
void buttonClear_Click(object sender, EventArgs e)
{
throw new NotImplementedException();
}
EDIT
the code for creating my panel is
var p = new Panel
{
BorderStyle = BorderStyle.FixedSingle ,
Size = new Size(506,100),
Name = "notifyPanel"
};
and the code for creating my FlowLayoutPanel is
var nFlowPanel = new FlowLayoutPanel
{
FlowDirection = FlowDirection.TopDown,
WrapContents = false,
AutoScroll = true,
Size = new Size(530, 377),
Location = new Point(13, 145)
};
and the code for my button clear is
void buttonClear_Click(object sender, EventArgs e)
{
var button = (Control)sender;
var panel = button.Parent.Controls["notifyPanel"];
panel.Dispose();
}
however it gives the error
Object reference not set to an instance of an object.
on the panel.Dispose() line.
anyone can help?
The Controls.Remove() method is very dangerous, it doesn't dispose the control. Which will live on, moved to the so-called parking window, using up both Windows and managed resources. After a bit less than 10,000 times doing this it crashes your program when Windows is no longer willing to let you create any more windows.
Call the control's Dispose() method instead. That also automatically removes the control from its container.
void buttonClear_Click(object sender, EventArgs e)
{
var panel = nFlowPanel.Controls["notifyPanel"];
panel.Dispose();
}
You can do it like this:
nFlowPanel.Controls.Remove((sender as Button).Parent);
I will suggest you to use List for this. Before adding Panels in the FlowLayoutpanel, add them in the List. Then just remove the indexed panel from the flowlayoutpanel.
Panel pnlTemp = (panel)list[index];
nFlowPanel.Controls.Remove(pnlTemp);
To get the index of the button you have to add your buttons also to your list and after clicking any button, search the button in the list and get the index of the button where it is saved in the list. If my code is unclear, let me know. but I feel your task is that complex. I am not sure but this link may be of some help.
Hope it helps.
I have a panel of labels, buttons and image that I wish to put into a flow layout panel.
As seen in some tutorial, I understand that it is possible to auto align new and additional buttons into a flow layout panel.
what I would like to ask is that is it possible to put a panel WITHIN a flow layout panel and call multiple instances of the same panel to appear within the flow layout panel.
My panel code would be
this.panelNotification.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.panelNotification.Controls.Add(this.button1);
this.panelNotification.Controls.Add(this.lblImage);
this.panelNotification.Controls.Add(this.lblName);
this.panelNotification.Controls.Add(this.lblLinkName);
this.panelNotification.Controls.Add(this.lblLinkLocation);
this.panelNotification.Controls.Add(this.lblLocation);
this.panelNotification.Location = new System.Drawing.Point(3, 3);
this.panelNotification.Name = "panelNotification";
this.panelNotification.Size = new System.Drawing.Size(506, 100);
this.panelNotification.TabIndex = 17;
So is it possible to include the whole panel into a flow layout panel? if yes, how do i do it. thank you.
Yes, you can put a Panel into a FlowLayoutoutPanel.
No, you can't put a control several times into a FlowLayoutoutPanel (in fact you can, but it is only displayed once).
But what you could do is writing some kind of Factory-Method that creates a new Panel with new Buttons/Labels/other Controls etc. every time you call it, and add these new instances to your FlowLayoutpanel. Something like this:
public class Form1
{
private Panel CreateNotificationPanel()
{
var p = new Panel { BackColor = Color.Red };
p.Controls.Add(new Button { Text = "Test" });
return p;
}
private void Form1_Load(System.Object sender, System.EventArgs e)
{
var flp = new FlowLayoutPanel { Dock = DockStyle.Fill };
flp.Controls.Add(CreateNotificationPanel());
flp.Controls.Add(CreateNotificationPanel());
flp.Controls.Add(CreateNotificationPanel());
this.Controls.Add(flp);
}
public Form1() { Load += Form1_Load; }
}
Another (and problably better) approach would be to create a UserControl that contains your Buttons/Labels/etc. instead of using a panel and adding all controls manually. Just create with the Designer and add new instances of the UserControl to the FlowLayoutPanel.