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!!
Related
I have multiple instances of the same User Control inside a stack panel, with a button in each user control.
When I click this button I want it to open a new window and then disable the stack panel containing all the user controls, such that multiple instance of this window can not be opened at the same time. I then want to be able to re-enable the stack panel upon the user closing the newly opened window.
Currently I have this code, when my button is inside of the Main Window XAML and not a part of the User Control:
private void ButtonClick(object sender, RoutedEventArgs e)
{
RouteViewer Rv = new RouteViewer((sender as Button).Tag).ToString());
Rv.Owner = this;
Rv.Show();
StackPanel.IsEnabled = false; //Disables the stackpanel
Rv.Closed += new EventHandler(RvClosed);
}
void RvClosed(object sender, EventArgs e)
{
StackPanel.IsEnabled = true; //Re-enables the stackpanel
}
As you can see the issue is due to the Stack Panel not being apart of the User Control. I've been googling and suspect the answer is something to do with routed events, any help would be appreciated.
Have a look at this website here, you will want to use event "Bubbling".
The code may look something like this:
C# In User Control:
private void ButtonClick(object sender, RoutedEventArgs e)
{
RouteViewer Rv = new RouteViewer(((sender as Button).Tag).ToString());
Rv.Show();
var newEventArgs = new RoutedEventArgs(RvOpenedEvent);
RaiseEvent(newEventArgs);
}
public static readonly RoutedEvent RvOpenedEvent = EventManager.RegisterRoutedEvent(
"RvOpened",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(ClassName));
public event RoutedEventHandler RvOpened
{
add { AddHandler(RvOpenedEvent, value); }
remove { RemoveHandler(RvOpenedEvent, value); }
}
Then in the Main Window XMAL :
<UserControl:Name RvOpened="RouteViewerOpened"/>
Then in the Main Window C#:
private void RouteViewerOpened(object sender, RoutedEventArgs e)
{
ServiceStack.IsEnabled = false;
e.Handled = true;
}
I have made a custom Number Keypad control that I want to place in my winform application. All of the buttons have an OnClick event to send a value to the focused textbox in my form where I have placed my custom control. Like this:
private void btnNum1_Click(object sender, EventArgs e)
{
if (focusedCtrl != null && focusedCtrl is TextBox)
{
focusedCtrl.Focus();
SendKeys.Send("1");
}
}
focusedCtrl is supposed to be set on the MouseDown event of the button like this:
private void btnNum1_MouseDown(object sender, EventArgs e)
{
focusedCtrl = this.ActiveControl;
}
where this.ActiveControl represents the active control on the form.
My problem is that the button always receives the focus before the event detects what the focused control was previously. How can I detect which control had the focus before the button got the focus? Is there another event I should be using? Thanks in advance!
EDIT: Also, I would rather not use the GotFocus event on each textbox in the form to set focusedCtrl since that can be tedious and because I would like to have all the coding of my custom control be in the control itself and not on the form where it is placed. (I will do this, though, if there is no other practical way to do what I am asking)
Your requirement is fairly unwise, you'll want some kind of guarantee that your button isn't going to poke text into inappropriate places. You really do need to have the form co-operate, only it knows what places are appropriate.
But it is not impossible, you can sniff at input events before they are dispatched to the control with the focus. In other words, record which control has the focus before the focusing event is fired. That's possible in Winforms with the IMessageFilter interface.
Add a new class to your project and paste the code shown below. Compile. Drop the new control from the top of the toolbox onto your form, replacing your existing buttons.
using System;
using System.Windows.Forms;
class CalculatorButton : Button, IMessageFilter {
public string Digit { get; set; }
protected override void OnClick(EventArgs e) {
var box = lastFocused as TextBoxBase;
if (box != null) {
box.AppendText(this.Digit);
box.SelectionStart = box.Text.Length;
box.Focus();
}
base.OnClick(e);
}
protected override void OnHandleCreated(EventArgs e) {
if (!this.DesignMode) Application.AddMessageFilter(this);
base.OnHandleCreated(e);
}
protected override void OnHandleDestroyed(EventArgs e) {
Application.RemoveMessageFilter(this);
base.OnHandleDestroyed(e);
}
bool IMessageFilter.PreFilterMessage(ref Message m) {
var focused = this.FindForm().ActiveControl;
if (focused != null && focused.GetType() != this.GetType()) lastFocused = focused;
return false;
}
private Control lastFocused;
}
Control focusedCtrl;
//Enter event handler for all your TextBoxes
private void TextBoxesEnter(object sender, EventArgs e){
focusedCtrl = sender as TextBox;
}
//Click event handler for your btnNum1
private void btnNum1_Click(object sender, EventArgs e)
{
if (focusedCtrl != null){
focusedCtrl.Focus();
SendKeys.Send("1");
}
}
you have an event called lostFocus you can use
button1.LostFocus +=new EventHandler(dataGridView1_LostFocus);
and in the event:
Control lastFocused;
void dataGridView1_LostFocus(object sender, EventArgs e)
{
lastFocused = sender as Control;
}
in that way you can always know what is the Control that was focused previously
now, correct me if i'm wrong, but you do it for the SendKeys.Send("1"); to know which textBox need to receive the number. for that you can use GotFocus event and register only the textBoxs to it.
you can also do what windows is doing and use just one textbox like here:
if it's fits your needs
What about using this with the parameter forward = false?
Control.SelectNextControl Method
You'd probably call it on your "custom Number Keypad control".
I have a solution with several forms, each may have TextBox's/controls and a button to show the SIP (the bottom bar is hidden).
When the user clicks my SIP button, the SIP is enabled but the focus is now the button. I want the user to click the button - the SIP to display but the focus to remain on the control that had the focus before the user clicked the button. Does anyone know how to do this? Thanks.
Instead of using an standard button, you can create a custom one by deriving from the Control class and overriding the OnPaint method. A control created this way will not claim the focus by default when treating the Click event (tested on VS2008 netcf 2.0).
public partial class MyCustomButton : Control
{
public MyCustomButton()
{
InitializeComponent();
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawString("Show SIP", Font, new SolidBrush(ForeColor), 0, 0);
// Calling the base class OnPaint
base.OnPaint(pe);
}
}
The solution of nathan will work also for Compact Framework or native Windows Mobile applications. In the textbox GotFocus set a global var and use this in the buttons click event to set the focus back to the last active textbox:
//global var
TextBox currentTB = null;
private void button1_Click(object sender, EventArgs e)
{
inputPanel1.Enabled = !inputPanel1.Enabled;
if(currentTB!=null)
currentTB.Focus();
}
private void textBox1_GotFocus(object sender, EventArgs e)
{
currentTB = (TextBox)sender;
}
regards
Josef
Edit: Solution with subclass of TextBox:
class TextBoxIM: TextBox{
public static TextBox tb;
protected override void OnGotFocus (EventArgs e)
{
tb=this;
base.OnGotFocus (e);
}
}
...
private void btnOK_Click (object sender, System.EventArgs e)
{
string sName="";
foreach(Control c in this.Controls){
if (c.GetType()==typeof(TextBoxIM)){
sName=c.Name;
break; //we only need one instance to get the value
}
}
MessageBox.Show("Last textbox='"+sName+"'");
}
Then, instead of placing TextBox use TextBoxIM.
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 am using a windows form and within the form i have a user control with two labels, one that has a message ENTER AMOUNT and the other where I am putting the values typed by the user (like when you go to an ATM) it starts showing the number .. it works fine if i dont have any other controls on the user control.. but the moment i add a button it does not work, it wont start showing the numbers as I use my numeric key pad.. but if i remove whatever button i added it works again... Here is my user control code.
public partial class OperationAmount : UserControl
{
public OperationAmount()
{
InitializeComponent();
}
private int _inputNumber = 0;
private void OperationAmount_Load(object sender, EventArgs e)
{
}
private void Form_KeyAmountPressed(object sender, KeyPressEventArgs e)
{
if (!Char.IsNumber(e.KeyChar))
{
return;
}
else if (lblOperationAmount.Text.Length > 9)
{
return;
}
else
{
_inputNumber = 10 * _inputNumber + Int32.Parse(e.KeyChar.ToString());
ReformatOutput();
}
}
private void ReformatOutput()
{
lblOperationAmount.Text = String.Format("{0:0.00}", (double)_inputNumber / 100.0);
}
}
Probably the new control steals the keypresses from your Form_KeyAmountPressed method because now it has the focus and receive the event KeyPress.
A simple workaround would be to add the method Form_KeyAmountPressed also at the KeyPress event of the button. Try also to set the TabStop property of the button to false. (not sure if this has any effect when the button is the only control that can get focus on your user control).