How can I make a window act like a Context Menu? - c#

I am trying to build a total new window acts as Context Menu.
the only problem i have is: when I am pressing the mouse buttons outside the window (ContextMenu), the window does not close. I can't find the event that can catch this action.
this is the code i am using now:
public partial class ContextMenu : Window
{
public ContextMenu()
{
InitializeComponent();
this.ShowInTaskbar = false;
this.Deactivated += new EventHandler(ContextMenu_Deactivated);
}
void ContextMenu_Deactivated(object sender, EventArgs e)
{
this.Hide();
}
protected override void OnDeactivated(EventArgs e)
{
base.OnDeactivated(e);
this.Hide();
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
this.Hide();
}
protected override void OnKeyDown(System.Windows.Input.KeyEventArgs e)
{
base.OnKeyDown(e);
this.Hide();
}
protected override void OnLostFocus(RoutedEventArgs e)
{
base.OnLostFocus(e);
this.Hide();
}
}
non of the functions above catches the mouse press outside the window (ContextMenu).
I have tried to use http://www.hardcodet.net/taskbar, but the examples I found are not something like what i am looking for.

Looks like you need processing of global mouse hooks.
Here is nice solution to this issue
http://www.codeproject.com/Articles/7294/Processing-Global-Mouse-and-Keyboard-Hooks-in-C

A control cannot detect mouse clicks that are outside their bounding Rectangles. However, the Window can detect a mouse click anywhere within its border. Therefore, all you need to do is to handle a PreviewMouseDown event in the MainWindow.xaml.cs file and then pass a message to the relevant control each time the event is raised.

I believe you'll want to use Mouse.Capture to detect a click away from your window.
This question+answer may lead you in the right direction:
How do I use CaptureMouse or Mouse.Capture in my C# WPF application?

Related

ToolStripDropDownMenu remains open after Form minimize and restore

I have Window Forms application and I'm using ToolStripDropDown as context menu for my form.
public partial class Form1 : Form
{
ToolStripDropDownMenu _formContextMenu = null;
public Form1()
{
InitializeComponent();
_formContextMenu = new ToolStripDropDownMenu();
_formContextMenu.Items.Add("Item1");
_formContextMenu.Items.Add("Item2");
}
protected override void OnMouseDown(MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
_formContextMenu.Show(e.Location);
}
else
base.OnMouseDown(e);
}
protected override void OnResize(EventArgs e)
{
_formContextMenu.Close();
base.OnResize(e);
}
}
First I click on form with Right Mouse button to show context menu. After that I press Win+D (minimize all windows) and then open my application again. Context menu remains opened and also it doesn't close when I click on form. I even can move form to other place but it will still remains opened.
I also tried to close it with different reasons.
_formContextMenu.Close(ToolStripDropDownCloseReason.AppClicked);
_formContextMenu.Close(ToolStripDropDownCloseReason.AppFocusChange);
_formContextMenu.Close(ToolStripDropDownCloseReason.CloseCalled);
_formContextMenu.Close(ToolStripDropDownCloseReason.ItemClicked);
_formContextMenu.Close(ToolStripDropDownCloseReason.Keyboard);
Doesn't help.
Can someone help with this issue?
I used this workaround for the problem and it works properly:
protected override void OnSizeChanged(EventArgs e)
{
if (this.WindowState == FormWindowState.Minimized)
{
//_formContextMenu or this.contextMenuStrip1
this.contextMenuStrip1.Visible = true;
this.contextMenuStrip1.Close();
}
base.OnSizeChanged(e);
}
While this problem also occurs for ContextMenuStrip but if there is not specific goal for using ToolStripDropDownMenu you can use ContextMenuStrip component and Set ContextMenuStrip property of form. This way you don't need to write code to show context menu.
But if in any reason you preferred showing in code, consider showing the context menu/ dropdown menu this way: yourContextMenu.Show(this,e.Location);

Prevent button getting focus

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.

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.

Hiding form when are other controls focus

This question is related to this my question. Now I have form in my class and when user click on button I show (or hide) form. That´s ok. But I want to hide form when I move with origin form or when I click somewhere in origin form. The new form is behind that origin form. I was trying events like lostfocus and others but It didn´t help. So I think I need some trick that check from my control if there was click in parrent form (origin form) or some other hack. I know the best would be that I put code but I have many lines so I think that best way will be if you help me in general way and then I try to applicate to my app.
You can do it with a global mouse and keyboard hook. In fact, its been wrapped up into well documented, well structured .NET API over at CodePlex
Go over there and download it. Then, set up a global mouse hook:
_mouseListener = new MouseHookListener(new GlobalHooker());
_mouseListener.MouseMove += HandleGlobalHookMouseMove;
_mouseListener.Start();
The key here is that you will receive the MouseMove event ANY time the mouse moves ANYWHERE on the desktop, not just within the bounds of your window.
private void HandleAppHookMouseMove(object sender, MouseEventArgs e)
{
if (this.Bounds.Contains(e.Location))
{
HandleEnter();
}
else
{
HandleLeave();
}
}
You can also setup one for MouseClick. The combination of the two will enable you to determine any time the mouse moves over your origin form, or the mouse is clicked when its over it. Unlike the LostFocus and other events you tried, focus is irrelevant.
Does below help?
public partial class Form1 : Form
{
Form f2 = new Form2();
public Form1()
{
InitializeComponent();
f2.Show();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (this.ClientRectangle.Contains(e.Location) && f2.Visible) { f2.Hide(); }
}
private void button1_Click(object sender, EventArgs e)
{
f2.Visible = !f2.Visible ? true : false;
}
}

Drawing rectangle does not work in Windows Forms

The program should draw a rectangle on click. But it does not. Maybe some problem with my understanding of delegates. What's the catch?
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace forms1
{
public partial class MainForm : Form
{
public MainForm()
{
//
// The InitializeComponent() call is required for Windows Forms designer support.
//
InitializeComponent();
//this.Paint+= new PaintEventHandler(MujPaintHandler);
this.Click += new EventHandler(MujClickHandler);
}
public void MujPaintHandler(object sender,PaintEventArgs e)
{
Graphics gfx=e.Graphics;
gfx.FillRectangle(new SolidBrush(Color.DarkViolet),100,100,200,200);
}
public void MujClickHandler(object sender,EventArgs e)
{
this.Text="aaaaa";
this.Paint+= new PaintEventHandler(MujPaintHandler);
}
}
}
The code you've written works for me, but your form's window has to be big enough to show the rectangle.
Diagnostically, the first thing I'd check is whether the title of the form changes to "aaaaa". If it does, then you know the click handler is being called - but maybe you've got a problem with the paint handler. If it doesn't, then for some reason your click handler isn't being called.
Note that this isn't the normal way you'd draw a rectangle on a click in Windows Forms, but I'm assuming this is just a learning exercise.
Try forcing a redraw after assigning the event handler:
public void MujClickHandler(object sender,EventArgs e)
{
this.Text="aaaaa";
this.Paint+= new PaintEventHandler(MujPaintHandler);
this.Invalidate();
}
Also, if you click twice, the event handler gets assigned twice, which is not something you want.
Maybe you have to force a redraw. Does the rect appear if you move the window? Just call the PaintHandler after click.
I think you are only attaching the Paint event handler. You are not invoking the Paint event.
Try this
public void MujClickHandler(object sender,EventArgs e)
{
this.Text="aaaaa";
this.Paint+= new PaintEventHandler(MujPaintHandler);
this.Invalidate();
}
It will only draw the rectangle if it happens to be inside the area that is invalidated to update the text that you change.
When you change the text, it creates a message that the text has to be redrawn, which will call the Paint event to do the drawing. The event will have a Graphics object that is clipped to the rectangle that needs to be redrawn to update the text, so only the part of the rectangle that intersects with the text will be drawn.
You have to cause a redraw that covers the entire rectangle, so the easiest is to cause the whole window to be redrawn:
this.Invalidate();
Note that you should not hook up the Paint event from the Click event handler. That means that the event will be hooked up one more time each click, so after five clicks the Paint event handler will be called five times every time something needs to be redrawn.
Looking at your code, I understand that you are trying to add an eventhandler for paint event on Click... You would also need to invoke the paint event.. Here is a sample code where I am assigning the Paint EventHandler on a button click and raising the paint event on the click as you are doing
public Form1()
{
InitializeComponent();
this.Click += new EventHandler(MujClickHandler);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.ControlKey)
{
MessageBox.Show(e.KeyCode.ToString());
}
}
private void Form1_Load(object sender, EventArgs e)
{
//this.Paint += new PaintEventHandler(MujPaintHandler);
}
public void MujPaintHandler(object sender,PaintEventArgs e)
{
Graphics gfx=e.Graphics;
gfx.FillRectangle(new SolidBrush(Color.DarkViolet),100,100,200,200);
}
public void MujClickHandler(object sender,EventArgs e)
{
this.Text="aaaaa";
this.RaisePaintEvent(this, new PaintEventArgs(this.CreateGraphics(), this.RectangleToClient(new Rectangle())));
}
private void button1_Click(object sender, EventArgs e)
{
this.Paint += new PaintEventHandler(MujPaintHandler);
}

Categories