Allow Mouse Wheel scroll on a TabPage Control - c#

A TabPage of a TabControl is populated with using a XML source. Once the XML contents are loaded into the TabPage, two ScrollBars appear on either side of the TabPage, to allow a user to scroll.
The user cannot scroll with the Mouse Wheel, though. I have checked the properties of the TabPage Control but I cannot find any property to assist with this.
Someone suggested to handle the MouseWheel event or override OnMouseWheel, but I'm not sure how this can be applied.
The gist of this is simple, how do I activate the Mouse wheel scroll on a tab page?
public partial class ModifyTransformerContentsView : Form
{
private readonly ITransformerConfigurationViewModel ViewModel;
public ModifyTransformerContentsView(ITransformerConfigurationViewModel viewModel)
{
InitializeComponent();
this.ViewModel = viewModel;
this.ViewModel.Notify += this.OnNotify;
this.xmlEditExampleStdfOutFile.SetFormateText(File.ReadAllText(this.ViewModel.SampleProcessingFilePath));
this.xmlEditExampleStdfOutFile.ReadOnly = true;
this.rtbXsl.SetFormateText(File.ReadAllText(this.ViewModel.TransformerFilePath));
this.rtbXsl.ReadOnly = false;
this.rtbXsl.RichTextBox.ClearUndo();
this.btnSave.Enabled = false;
this.rtbCheatSheet.Text = File.ReadAllText(this.ViewModel.CheatSheetFilePath);
}
private void OnValidateClick(object sender, System.EventArgs e)
{
this.ViewModel.SetTemporaryTransformerFileContents(this.rtbXsl.Text);
this.ViewModel.ValidateXsl(this.rtbXsl.Text,
validationSuccessful =>
{
this.btnSave.Enabled = validationSuccessful;
this.rtbExampleOutputFileContents.SetFormateText(this.ViewModel.ExampleFileOutputContents);
});
}
private void OnSaveClick(object sender, System.EventArgs e) => this.ViewModel.Save(this.rtbXsl.Text);
private void OnNotify(NotificationEventArgs obj)
{
switch (obj.NotificationType)
{
case NotificationType.Info:
MessageBox.Show(obj.Message, "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
if (obj.Exit)
{
this.Close();
}
break;
case NotificationType.Warning:
MessageBox.Show(obj.Message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
break;
case NotificationType.Error:
MessageBox.Show(obj.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
if (obj.Exit)
{
this.Close();
}
break;
}
}
private void ModifyTransformerContentsView_FormClosing(object sender, FormClosingEventArgs e)
=> this.ViewModel.DeleteTemporaryModifiedTransformerFile();
private void OnButtonCheatSheetSaveClick(object sender, System.EventArgs e) =>
this.ViewModel.SaveCheatSheet(rtbCheatSheet.Text);
private void ModifyTransformerContentsView_Load(object sender, System.EventArgs e)
{
}
}
Any assistance would be appreciated.

The TagPage Control class is derived from the Panel class.
This type of Control is not selectable (ControlStyles.Selectable is set to false in its Constructor), so it doesn't receive focus and cannot be selected with a Mouse click.
You can override this behavior in different ways. Three simple methods:
Build a Custom Control derived from TabPage then:
in its Constructor, call SetStyle():
SetStyle(ControlStyles.Selectable |
ControlStyles.UserMouse |
ControlStyles.StandardClick, true);
Create an instance of this Custom Control and add it to the TabPages of a TabControl
Build a Custom Control derived from Panel:
Set the same ControlStyles in its Constructor
Build the Control, find it in the ToolBox and drop it inside a TabPage, then set Dock = DockStyle.Fill and AutoScroll = true (or do this directly in the Custom Control class).
Add all child Controls to this Panel.
Using Reflection, get the non-public SetStyle method of a TabPage and use MethodInfo.Invoke() to change the values. e.g.,:
using System.Reflection;
var flags = BindingFlags.NonPublic | BindingFlags.Instance;
var method = tabPage1.GetType().GetMethod("SetStyle", flags);
var newStyles = ControlStyles.Selectable | ControlStyles.UserMouse;
method.Invoke(tabPage1, new object[] { newStyles, true });
You can do this to all TabPages in a loop.

Related

Do I have a memory Leak, in my FlowLayoutPanel?

I am using FlowLayoutPanels. One user control has a FlowLayoutPanel, and when a button is clicked on that panel a Custom User Control is created and added to that flowlayout. Inside that Custom User Control I have a button customButton2 and a handler customButton2_Click. And when customButton2 clicked I want to remove the current UserControl from that FlowLayout. As you can see I tried to disposed them inside customButton2_Click. However when I add or remove a custom user control, memory usage increases. As I said even if I delete something it increase the memory. I wrote a dispose and -= event handler for that button but nothing changes! Doesn't matter if I add or remove, memory usage increase no matter what. This is my main problem. Could you please help me with that?
My main user control that has the FlowLayoutPanel object. Moreover this control adds the custom user controls to FlowLayout
public partial class TodoList : UserControl
{
public TodoList()
{
InitializeComponent();
TodoListFlowLayout.HorizontalScroll.Enabled = false;
TodoListFlowLayout.HorizontalScroll.Visible = false;
TodoListFlowLayout.HorizontalScroll.Maximum = 0;
TodoListFlowLayout.AutoScroll = true;
}
public void button1_Click(object sender, EventArgs e)
{
if (this.TodoListFlowLayout.Controls.Count >= CommonVariables.TotalNumberOfTodoElement)
{
// Some Error message
return;
}
TodoListPanel todoPanel = new TodoListPanel(TodoListFlowLayout);
TodoListFlowLayout.Controls.Add(todoPanel);
TodoListFlowLayout.Invalidate();
}
}
My custom user control:
public partial class TodoListPanel : UserControl
{
System.Windows.Forms.FlowLayoutPanel flowLayoutPanel;
public TodoListPanel(System.Windows.Forms.FlowLayoutPanel flowLayout)
{
// This control has 1 label 2 custom buttons and a one panel.
InitializeComponent();
this.label1.Click += todo_Element_Panel_Click;
this.customPanel1.Click += todo_Element_Panel_Click;
flowLayoutPanel = flowLayout;
}
private void customButton2_Click(object sender, EventArgs e)
{
this.customPanel1.Click -= todo_Element_Panel_Click;
this.customButton2.Click -= customButton2_Click;
this.customButton1.Click -= customButton1_Click;
this.label1.Click -= todo_Element_Panel_Click;
foreach (TodoListPanel control in flowLayoutPanel.Controls)
{
if (this == control)
control.Dispose();
}
this.customPanel1.Dispose();
this.customButton2.Dispose();
this.customButton1.Dispose();
this.label1.Dispose();
this.Dispose();
this.flowLayoutPanel.Controls.Remove(this);
}
private void customButton1_Click(object sender, EventArgs e)
{
// Somethings happening
}
void todo_Element_Panel_Click(object sender, EventArgs e)
{
// Somethings are happening here too
}
}
How can I handle this memory leak? Or Do I really have a memory leak? Please see my Diagnostic tool:
After yellow pointer shows up which indicates the Garbadge Collecter is running, I removed bunch of custom user controls, even if I removed them the memory usage increased!!

How to change BackColor of all my Panel in my Form

I need help with my tool.
I have try change Color my Panel with ColorDialog but, it does not work
I want change colors all Panel in my Form.
Panel constuctor:
Panel p = new Panel();
Event handlers:
private void button104_Click_1(object sender, EventArgs e)
{
this.bg.FullOpen = true;
if (this.bg.ShowDialog() == DialogResult.OK)
{
this.setBgColor(this.bg.Color);
}
}
public void setBgColor(Color rgb)
{
p.BackColor = rgb;
}
You can select all controls of a particular type by using the System.Linq extension method, OfType, and if you iterate over them in a loop, you can set all their BackColor properties:
private void button1_Click(object sender, EventArgs e)
{
ColorDialog cd = new ColorDialog();
if (cd.ShowDialog() == DialogResult.OK)
{
foreach (var panel in Controls.OfType<Panel>())
{
panel.BackColor = cd.Color;
}
}
}
Note that this only iterates over the controls belonging directly to the form itself. If any of the panels are inside a container control, then we will need to look through each control to see if it contains any panels.
We can write a helper method for this that takes in a Control to inspect, a Color to use for the BackColor, and a Type that specifies the type of control we want to set the back color for.
Then we first check if the Control is the same type as the one we're looking for, and if it is, set it's backcolor. After that, we loop through all it's children and recursively call the method again on them. This way, if we pass the parent form as the Control, we will iterate through all the controls:
private void SetBackColorIncludingChildren(Control parent, Color backColor, Type controlType)
{
if (parent.GetType() == controlType)
{
parent.BackColor = backColor;
}
foreach(Control child in parent.Controls)
{
SetBackColorIncludingChildren(child, backColor, controlType);
}
}
private void button1_Click(object sender, EventArgs e)
{
ColorDialog cd = new ColorDialog();
if (cd.ShowDialog() == DialogResult.OK)
{
// Pass 'this' to the method, which represents this 'Form' control
SetBackColorIncludingChildren(this, cd.Color, typeof(Panel));
}
}
You can use this:
private void button1_Click(object sender, EventArgs e)
{
this.bg.FullOpen = true;
if ( this.bg.ShowDialog() == DialogResult.OK )
{
setBgColor(Controls, bg.Color);
}
}
public void setBgColor(Control.ControlCollection controls, Color rgb)
{
foreach ( Control control in controls )
{
if ( control is Panel )
( (Panel)control ).BackColor = rgb;
setBgColor(control.Controls, rgb);
}
}
It parses all controls of the form and for each it parses all controls of the controls recursively.
Then the color of all panels of the form is changed, all "root" panels and all panels in panels in panels in panels...
This looks like winforms. Assuming this is the case, you need to iterate over all the controls on the form, and for each that is a Panel, set its color.
Something like this (untested, you may need to play about a bit )
public void setBgColor(Color rgb)
{
foreach (Control c in this.Controls)
{
if (c.GetType() == typeof(System.Windows.Forms.Panel))
{
c.BackColor = rgb;
}
}
}

Detect SplitContainer's select Panel

I have Windows Form named Form1 and inside I have a dynamic SplitContainer named splitcontainer.
I want to know which panel is selected when the mouse is clicked at runtime.
I tried to use mouseclick event in the splitContainer properties but I haven't succeed.
You need to bind to the MouseClick events of the panel inside the split container.
I added a container called "splitContainer1" with 2 panels, Panel1 and 2
I wired up the below events and it seems to work
private void splitContainer1_Panel1_MouseClick(object sender, MouseEventArgs e)
{
MessageBox.Show("Panel1");
}
private void splitContainer1_Panel2_MouseClick(object sender, MouseEventArgs e)
{
MessageBox.Show("Panel2");
}
After your further comments, I've edited the below to show how to manually bind the mouse click events of the 2 panels of your dynamically added container.
private void splitContainerHorizontalToolStripMenuItem_Click(object sender, EventArgs e)
{
SplitContainer spltcnt = new SplitContainer();
spltcnt.Dock = DockStyle.Left;
spltcnt.Orientation = Orientation.Horizontal;
spltcnt.SplitterWidth = 4;
spltcnt.Visible = true;
spltcnt.Size = new System.Drawing.Size(731, 615);
spltcnt.BorderStyle = BorderStyle.Fixed3D;
spltcnt.SplitterDistance = 351;
//Manually bind the mouse click events.
spltcnt.Panel1.MouseClick += Panel1OnMouseClick;
spltcnt.Panel2.MouseClick += Panel2OnMouseClick;
Controls.Add(spltcnt);
}
private void Panel1OnMouseClick(object sender, MouseEventArgs mouseEventArgs)
{
MessageBox.Show("Panel1");
}
private void Panel2OnMouseClick(object sender, MouseEventArgs mouseEventArgs)
{
MessageBox.Show("Panel2");
}
You can of course call the mouse click handler methods anything you like.
Thanks

Windows Forms Remove Close Button

I'm working on a Windows Forms app and I'm wanting to remove the close button from the top. I'm aware of the ControlBox option, but I'm wanting to provide a help button. Is there a way to have the Close button not visible while maintaining the help button?
Your best bet may be to subcribe to the FormClosing event of the form like so and cancel the closing action:
// In your code somewhere subscribe to this event
Form1.FormClosing += Form1_FormClosing;
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
e.Cancel = true;
}
The benefit of doing this is that it prevents the user from closing the application from the close button and the taskbar.
Obviously you don't want to ALWAYS cancel the form from closing. So you will want to set some type of boolean flag that you will check in the event listener as to whether you want the form to be allowed to close or not. Example:
void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (BlockClosing)
e.Cancel = true;
}
EDIT: If you don't want to approach the problem that way, and you really do intend to completely remove the close button, then your best bet is to create your own custom title bar. In that case, you set the form's FormBorderStyle property to None. And you then dock your custom title bar to the top of the form. Here is some sample code from one I made a while back:
using System;
using System.ComponentModel;
using System.Windows.Forms;
namespace Spectrum.UI
{
public partial class TitleBar : UserControl
{
public delegate void EventHandler(object sender, EventArgs e);
public event EventHandler MinButtonClick;
public event EventHandler MaxButtonClick;
public event EventHandler CloseButtonClick;
#region Properties
[Category("Appearance")]
public string Title
{
get { return TitleLabel.Text; }
set { TitleLabel.Text = value; }
}
[Category("Appearance")]
public bool MinimizeEnabled
{
get
{
return minButton.Visible;
}
set
{
minButton.Visible = value;
}
}
[Category("Appearance")]
public bool MaximizeEnabled
{
get
{
return maxButton.Visible;
}
set
{
maxButton.Visible = value;
}
}
#endregion
public TitleBar()
{
InitializeComponent();
ShowTitleBarImage = false;
}
#region Mouse Events
private void TitleBar_MouseDown(object sender, MouseEventArgs e)
{
this.OnMouseDown(e);
}
private void TitleBar_MouseUp(object sender, MouseEventArgs e)
{
this.OnMouseUp(e);
}
private void TitleBar_MouseMove(object sender, MouseEventArgs e)
{
this.OnMouseMove(e);
}
#endregion
#region Button Click Events
private void minButton_Click(object sender, EventArgs e)
{
if (MinButtonClick != null)
this.MinButtonClick.Invoke(this, e);
}
private void maxButton_Click(object sender, EventArgs e)
{
if (MaxButtonClick != null)
this.MaxButtonClick.Invoke(this, e);
}
private void closeButton_Click(object sender, EventArgs e)
{
if (CloseButtonClick != null)
this.CloseButtonClick.Invoke(this, e);
}
#endregion
}
}
As you can see from the image, I also added a background image to the control. Depending on your patience and your requirements, you can use images and PictureBox controls to make this look as much like a standard title bar as you need.
In the above example I placed three buttons on the control with images I found online to represent minimize, maximize, and close. in your case you would simply exclude a close button. I also placed a string on the control with an appropriate font to serve as the title of the window.
Adding the custom title bar to your form is easy.
public TitleBar titleBar = new TitleBar();
titleBar.Dock = DockStyle.Top;
titleBar.MaximizeEnabled = true;
titleBar.MinimizeEnabled = true;
titleBar.Size = new System.Drawing.Size(10, 40); // Width doesn't matter - I wanted it 40 pixels tall
titleBar.Title = "Title Example";
titleBar.MinButtonClick += titleBar_MinButtonClick;
titleBar.Max ButtonClick += titleBar_MaxButtonClick;
this.Controls.Add(this.TitleBar);
And then last step is to set up your event listeners for the min and max button clicks:
private void titleBar_MinButtonClick(object sender, EventArgs e)
{
WindowState = FormWindowState.Minimized;
}
private void titleBar_MaxButtonClick(object sender, EventArgs e)
{
WindowState = FormWindowState.Maximized;
}
You may also note that I included events for mouse down, up and move in my title bar. This was so that I could create listeners in my form to move the form when the user clicked and dragged the title bar. This is optional and depends on if you need the user to be able to move your application window.
The added benefit of doing this is that can use the title bar for additional controls. For example, my application was custom written for use on a toughbook style tablet computer with a small touchscreen display. In my application, utilization of the limited space was extremely important. I was able to further modify what I've described here to also include menu bar style control directly on the title bar. In addition, I added more buttons to the left of the stand minimize, maximize, and close buttons. Really helped me utilize every square inch of the screen in my application. Couldn't have done it with the standard title bar.
Can you simply use Form.ControlBox = false (or via the designer as you point out rather negatively in your comment) and then add a custom help button on the form?
EDIT: A colleague of mine wrote an Excel add in and had a requirement to remove the X from certain forms (e.g. a Progress Bar that shouldn't be closed). He found a function written by Stephen Bullen that did just that. I've only seen this function used in VB, but perhaps you can get some ideas or direction out of his approach of using Windows API to solve your issue.
This code will disable the Close button. I am not sure if you can actually make it invisible. http://www.codeproject.com/Articles/20379/Disabling-Close-Button-on-Forms
//
// source code
// Code Snippet
private const int CP_NOCLOSE_BUTTON = 0x200;
protected override CreateParams CreateParams
{
get
{
CreateParams myCp = base.CreateParams;
myCp.ClassStyle = myCp.ClassStyle | CP_NOCLOSE_BUTTON ;
return myCp;
}
}
Good luck!
Please try this.ControlBox = false.

i want to dock User Control

I have make user control and inside that user control takes two buttons name dock and close respectively.
Now i want to dock my user control to left when i clicks button dock and close my user control when i clicks button close..
(i am trying to use by making object of user control but doesnt helps.....)
void button1_Click(object sender, EventArgs e) {
Container1 obj = new Container1();
if (obj.Dock != DockStyle.None) {
obj.Dock = DockStyle.None;
MessageBox.Show("Dockstyle is None");
}
else {
obj.Dock = DockStyle.Left;
MessageBox.Show("Dockstyle is Left");
}
}
obj needs to be a reference to the instance of your already existing userControl (in your case, the this keyword). You have created a new instead of the Container1 here.
private void button1_Click(object sender, EventArgs e)
{
if (this.Dock != DockStyle.None)
{
this.Dock = DockStyle.None;
MessageBox.Show("Dockstyle is None");
}
else
{
this.Dock = DockStyle.Left;
MessageBox.Show("Dockstyle is Left");
}
}
You don't want to create the container and then set the DockStyle on that container. Instead, you need to set the DockStyle of the UserControl itself.

Categories