Right click menu and menu line - c#

Goal:
Right clicking in the listview and choose different option.
Problem:
There are two problem:
*When I'm right clicking, the left corner of the menu is not exactly located in the arrow's spot location.
*How do I create a line in the menu?
The main problem about the menu
Need support to create these two redmark.
private void lstV_Stock_MouseUp(object sender, MouseEventArgs e)
{
switch (e.Button)
{
// Right mouse click
case MouseButtons.Right:
ContextMenu myContextMenu = new ContextMenu();
MenuItem menuItem1 = new MenuItem("New product");
MenuItem menuItem2 = new MenuItem("Delete");
MenuItem menuItem3 = new MenuItem("Add quantity");
// Clear all previously added MenuItems.
myContextMenu.MenuItems.Clear();
myContextMenu.MenuItems.Add(menuItem1);
myContextMenu.MenuItems.Add(menuItem2);
myContextMenu.MenuItems.Add(menuItem3);
if (lstV_Stock.SelectedItems.Count > 0)
{
foreach (ListViewItem item in lstV_Stock.SelectedItems)
{
myContextMenu.MenuItems[1].Visible = true;
myContextMenu.MenuItems[2].Visible = true;
myContextMenu.MenuItems[0].Visible = false;
}
}
else
{
myContextMenu.MenuItems[1].Visible = false;
myContextMenu.MenuItems[2].Visible = false;
myContextMenu.MenuItems[0].Visible = true;
}
myContextMenu.Show(lstV_Stock, this.PointToClient(Cursor.Position), LeftRightAlignment.Right);
menuItem1.Click += new System.EventHandler(this.menuItem1_Click);
break;
}

For the positioning, you can replace your
myContextMenu.Show(lstV_Stock, this.PointToClient(Cursor.Position), LeftRightAlignment.Right);
to
myContextMenu.Show(lstV_Stock, e.Location(), LeftRightAlignment.Right);
or the point e.X,e.Y. Not from this.PointToClient, but from the MouseEventArgs generating the event. You can check wahat MouseEvent have here.

To create a "line" you have to create a MenuItem with text "-"

Problem
If you just set the ListView.ContextMenu property and remove all your own right-click code, the menu should show up correctly.
For the line you need a ToolStripSeparator item. The designer will create one when you type '-' as the Text. You can drag them in the designer.

So, using a ContextMenu is the way to go here. Those "Lines" you're referring to are called Separaters.
If you're creating the COntext Menu in Design View, then click the Context Menu, then right-click inside the menu, and click Insert > Separater.
You can then drag it up or down, or into a sub-menu if you wish.

Related

How to use a WPF ContextMenu with NotifyIcon

I want to open a WPF ContextMenu when the user clicks the system tray icon. With Windows Forms this is straight-forward, just call notifyIcon.ContextMenu = contextMenu and you're set.
On WPF we can not set the ContextMenu that easily because WPF's ContextMenu class is not related to Forms ContextMenu. The alternative I have been pursuing is to handle NotifyIcon's Click event to open the WPF-style ContextMenu.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// This is intended to be a system tray application so we hide the window
this.Visibility = Visibility.Hidden;
// Winform context menu
// The context menu closes when the user clicks anywhere outside the menu
// The user can navigate the menu with the keyboard arrows and close with ESC
var notifyIcon1 = new System.Windows.Forms.NotifyIcon();
var contextMenu = new System.Windows.Forms.ContextMenu();
var menuItem = new System.Windows.Forms.MenuItem();
menuItem.Text = "WinForm Menu Item";
contextMenu.MenuItems.Add(menuItem);
notifyIcon1.ContextMenu = contextMenu;
notifyIcon1.Icon = Properties.Resources.ico;
notifyIcon1.Visible = true;
// WPF context menu
// The user cannot close the menu by clicking outside its bounds
// Does not detect any keyboard input
var notifyIcon2 = new System.Windows.Forms.NotifyIcon();
notifyIcon2.Icon = Properties.Resources.ico;
notifyIcon2.Visible = true;
notifyIcon2.Click += NotifyIcon2_Click;
}
private void NotifyIcon2_Click(object sender, EventArgs e)
{
var contextMenu = new ContextMenu();
var menuItem = new MenuItem();
menuItem.Header = "WPF Menu Item";
contextMenu.Items.Add(menuItem);
contextMenu.IsOpen = true;
}
}
The issue with this approach is that the WPF ContextMenu never gets any hint that the user has navigated away from the menu and should close (Eg, when the user clicks outside the bounds of the menu). None of the Focus or MouseCapture events are ever triggered and I am unable to close the menu other than by clicking on one of its items.
So the question here, to put slightly different, is: how do I properly emulate the NotifyIcon's ContextMenu closing behavior using WPF's ContextMenu?
I faced similar issue. You can try if you want
notifyIcon1.ContextMenuStrip = new Forms.ContextMenuStrip();
notifyIcon1.ContextMenuStrip.Items.Add("YourMenuItem",null, MenuItemEvent);
I hope this will solve the problem.

Open Tab Pages on Button Click in Winform C#

I have several tab pages collection. By default when user open the apps, the first tab page is the start tab page, then user will close the tab page. Now I would like to create a situation where when the user go to the menu strip, click for example the "tab page 1 button", then the "tab page 1" will appear in the tab control. Any expertise can help me please...
Use the SelectedTab() method. It has three overloads.
If you have a reference to the tab:
tabControl1.SelectTab(tabPage2);
If you only know the index:
tabControl1.SelectTab(1); // 0-based index, this shows the second tab
If you only know the name:
tabControl1.SelectTab("tabPage2");
You say your users can click an [x] that removes the tab.
I'll assume it's removed by the easiest means, something like:
tabControl1.TabPages.Remove(tabPage1);
You can't focus on a tab that's not part of the tab control, so you'll have to add it back first.
tabControl1.TabPages.Add(tabPage1); // add tab as last tab in tabcontrol
tabControl1.TabPages.Insert(0, tabPage1); // or insert it at a specific index
tabControl1.SelectTab(tabPage1);
To select the tab page of the TabPage control, not only could user click the title to switch pages, but set the selectedTabPageIndex property (or like this) to do it.
Just have a try.
i am also facing this problem. Finally i solve by following code.
Scenario
My tab Control have many tabs and i make a [x] sign for closing that tab.
on click [x] my tab is remove from Tab Control.
Now when i click on button, i open the tab (that was Removed)
Code
private void openProductTab_Click(object sender, EventArgs e)
{
if (tabControlMdi.TabPages.Contains(tabProduct))//tab already present
{
tabControlMdi.SelectTab(tabProduct); // select by name
}
else
{
tabControlMdi.TabPages.Add(tabProduct); // add removed tab
tabControlMdi.SelectTab(tabProduct); // select by name
}
}
private void invoiceGenerationToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Form form in Application.OpenForms)
{
if (form.GetType() == typeof(RETransactions.frmInvoicegeneration))
{
form.Activate();
foreach (TabPage item in tabControl1.TabPages)
{
if (item.Text == "Invoice Generation")
{
tabControl1.SelectTab(item);
}
}
return;
}
}
RETransactions.frmInvoicegeneration rTenancy = new RETransactions.frmInvoicegeneration();
rTenancy.Show();
rTenancy.TopLevel = false;
TabPage tabp = new TabPage("Invoice Generation");
tabp.Controls.Add(rTenancy);
tabControl1.TabPages.Add(tabp);
tabControl1.SelectTab(tabp);
tabp.BackColor = Color.Gainsboro;
}
// i hope it will work ... thank you

Changing Cursor Dynamically according to the control

I am creating a custom control. On that control I have around 20 sub controls. When i move the cursor on my User Control, i want the cursor to be changed according to sub control it is moving on.
Eg:
User Control
--Control 1 : if(Condition 1) { Mouse - Wait } else { Mouse - Default }
--Control 2 : if(Condition 1) { Mouse - Hand } else { Mouse - Default }
--Control 3 : Mouse - Default
......so on.
Is there any way to determine on MouseMove Event of User Control that i am moving on which sub control so that i can change my cursor in a single event.
You don't need to rely on events, can use the Cursor Property of the given control. For example, if you have three TextBoxes, you can change this property in the "properties box" on the "Design View" or just write:
textBox1.Cursor = Cursors.WaitCursor;
textBox2.Cursor = Cursors.Hand;
textBox3.Cursor = Cursors.Default;
The cursor would show the given shape when "entering" in each Textbox.
You can assign to EACH usercontrol's mouse-over or You can assign to ONE event handler, which is the same for all Your controls. Depending on which technique You choose, You then can set the cursor, the second technique requires to a ) a hardcoded if / else or switch case or b ) reflection casting sender to right type and then setting the mouse-cursor.
Did this help ?
You can do this way. Suppose you have three buttons having name as button1, button2 & button3.
Write this on form load
this.button1.MouseHover += new System.EventHandler(this.MouseHover);
this.button2.MouseHover += new System.EventHandler(this.MouseHover);
this.button3.MouseHover += new System.EventHandler(this.MouseHover);
Now write this as new event :
private void MouseHover(object sender, EventArgs e)
{
Button oButton = (Button)sender;
if (oButton.Name == "button1")
{
oButton.Cursor = Cursors.WaitCursor;
}
else if (oButton.Name == "button2")
{
oButton.Cursor = Cursors.Hand;
}
else if (oButton.Name == "button3")
{
oButton.Cursor = Cursors.Default;
}
}
It will work as you need.
Thanks

Jumping to next tab

I have a tab control in my WPF application with multiple tabs. Each tab gives access to several buttons, text boxes, drop downs. Now before moving to the next tab valid entries in each of the controls in the tab is to be checked or jumping to the next tab should not be allowed. How can this be done?
I was able to use IsEnable property to do this. But I want it like, when I click on the next tab it should, without entering the next tab, display a warning that such and such entry in the present tab is not valid.
If you adhere to the Selected event you can do something like this:
// Keep a global variable for the previous index
int prevIndex = 0;
private void tabControl_Selected(object sender, TabControlEventArgs e)
{
TabControl tc = sender as TabControl;
if (tc != null)
{
bool letSwitchHappen = validateTabControls(tc.SelectedIndex);
if (!letSwitchHappen)
{
tc.SelectedIndex = prevIndex;
}
prevIndex = tc.SelectedIndex;
}
}
Where validateTabControls is something like:
private bool validateTabControls(int tabIndex)
{
bool validEntries = false;
// Some code here to set validEntries according to the control at tabIndex
return validEntries;
}
Take a look at this example from Josh Smith.
It shows explicitly how to do this, and Josh is well-known (and respected) in the WPF world.

ToolStripMenuItem for multiple ContextMenuStrip

I have a form which contains tab panel with many tap pages. Each of them has its own context menu (display on right-click). But If I add a ToolStripMenuItem to multiple ContextMenuStrips only last menu strip really has this menu item.
Simple code example is:
ToolStripMenuItem tim_refresh = new ToolStripMenuItem("Refresh", null, (o, e) =>
{
MessageBox.Show("Refresh");
});
ContextMenuStrip cms1 = new ContextMenuStrip();
cms1.Items.Add(tim_refresh);
ContextMenuStrip cms2 = new ContextMenuStrip();
cms2.Items.Add(tim_refresh);
this.tblDataManagerObjects.ContextMenuStrip = cms1;
this.tblDataSourceTypes.ContextMenuStrip = cms2;
If one shows this menus one by one, first will be empty...How can I achieve what I want?
Thi is because visual can not be child of multiple diferent visuals in the same time. In your case tim_refresh is a child of cms1 and cms2 at the same time.
You need to create two completely separate instances of ToolStripMenuItem.
EDIT:
You can extract visual creation in factor method to simplify multiple objects instantiation:
private ToolStripMenuItem CreateToolStripMenuItem(string name)
{
return new ToolStripMenuItem(name, null, (o, e) =>
{
MessageBox.Show(name);
});
}
// then just call it once per each menu strip
ContextMenuStrip cms1 = new ContextMenuStrip();
cms1.Items.Add(CreateToolStripMenuItem("Refresh"));
ContextMenuStrip cms2 = new ContextMenuStrip();
cms2.Items.Add(CreateToolStripMenuItem("Refresh"));
one context menu is displayed once at a time; you probably don't need many clones everywhere, but you may want to move one single instance of your menu items to the menu menu strip at the moment menu strip is opening;
I'm moving here the named (grand) parent's items to the child (currently opening) menu when the local copy is empty, and all the next ctx openings I just AddRange, which moves the "located" three menu items from the previously opened ctxMenuStrip to the currently-opening-one:
// http://stackoverflow.com/questions/8307959/toolstripmenuitem-for-multiple-contextmenustrip?rq=1
// http://stackoverflow.com/questions/6275120/toolstripmenuitem-added-to-several-places?rq=1
// WILL_ADD_PARENT_MENU_ITEMS_IN_Opening first time opened we locate common menu items from GrandParent, then we move them to the current slider; cool?
private static ToolStripItem[] separatorLoadSave = null;
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) {
if (separatorLoadSave == null) {
separatorLoadSave = new ToolStripItem[3];
Control slidersAutoGrow = base.Parent;
if (base.Parent.Name != "SlidersAutoGrow") return;
Control slidersForm = slidersAutoGrow.Parent;
if (slidersForm.Name != "SlidersForm") return;
ToolStripItem[] separator = slidersForm.ContextMenuStrip.Items.Find("toolStripSeparator1", false);
if (separator.Length > 0) separatorLoadSave[0] = separator[0];
ToolStripItem[] load = slidersForm.ContextMenuStrip.Items.Find("mniParameterSetLoad", false);
if (load.Length > 0) separatorLoadSave[1] = load[0];
ToolStripItem[] save = slidersForm.ContextMenuStrip.Items.Find("mniParameterSetSave", false);
if (save.Length > 0) separatorLoadSave[2] = save[0];
}
this.contextMenuStrip1.SuspendLayout();
this.contextMenuStrip1.Items.AddRange(separatorLoadSave);
this.contextMenuStrip1.ResumeLayout();
}

Categories