Context menu shows changes on next click - c#

I am using a DevExpress TreeList. I have two methods MouseDown() and MouseUP() to get the item from the treelist by right click and then show a contextmenu/popup menu with changes to it at runtime.
Problem: ContextMenu or PopupMenu displays the barSubItem3.Enabled = false;change on the next click. Not on the current click.
private void TreeList1_MouseDown(object sender, MouseEventArgs e)
{
TreeList tree = sender as TreeList;
if (e.Button == MouseButtons.Right && ModifierKeys == Keys.None
&& tree.State == TreeListState.Regular)
{
Point pt = tree.PointToClient(MousePosition);
TreeListHitInfo info = tree.CalcHitInfo(pt);
if (info.HitInfoType == HitInfoType.Cell)
{
SavedFocused = new TreeListNode();
SavedFocused = tree.FocusedNode;
tree.FocusedNode = info.Node;
/* get value from node that is clicked by column index */
switch (SavedFocused.GetValue(0).ToString())
{
case "A":
barSubItem3.Enabled = false;
break;
case "B":
barSubItem3.Enabled = true;
break;
}
}
}
}
private void TreeList1_MouseUp1(object sender, MouseEventArgs e)
{
TreeList tree = sender as TreeList;
if (e.Button == MouseButtons.Right && ModifierKeys == Keys.None
&& tree.State == TreeListState.Regular)
{
popUpMenu.ShowPopup(MousePosition);
}
}

I guess that's happening because you're actually modifying the state of the item once it's already being shown.
Use the PopupMenuShowing event instead. Here is an example on how to modify the PopUpMenu using a GridView.
private void Whatever_PopupMenuShowing(object sender, DevExpress.XtraGrid.Views.Grid.PopupMenuShowingEventArgs e)
{
var menu = e.Menu;
var hi = e.HitInfo;
if (!(sender is GridView view))
return;
var inDetails = (hi.HitTest == GridHitTest.EmptyRow);
if (menu == null && inDetails)
{
menu = new DevExpress.XtraGrid.Menu.GridViewMenu(view);
e.Menu = menu;
}
if (menu == null)
return;
//If there are any entries, show "Duplicate" button
var rowHandle = hi.RowHandle;
if (!view.IsDataRow(rowHandle)) return;
var mnuDuplicate = new DXMenuItem("Duplicate",
async delegate { await ClickDuplicate(); },
Properties.Resources.copy_16x16)
{
BeginGroup = true
};
menu.Items.Add(mnuDuplicate);
}

Related

C# How to stop selecting an item from list box

quick question: When I click anywhere on the list box (Not clicking on the items) it automatically selects the first item, how can I remove this? I want the user to select a specific item.
Thanks!
Code:
private void FriendsLb_Click(object sender, EventArgs e)
{
var obj = FriendsLb.SelectedItem;
if (obj != null)
{
FriendsLb.MouseDown += FriendsLb_MouseDown;
}
}
private void FriendsLb_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
var item = FriendsLb.IndexFromPoint(e.Location);
if (item >= 0)
{
try {
FriendsLb.SelectedIndex = item;
userRightClick.Show(FriendsLb, e.Location);
}
catch { return; } // No item selected
}
}

Show Sub Menu on right Click On DataGridView - C#

Hi I added a right click event on my datagridview which shows menu but I want to show a sub menu when clicked or mouse hover on one of the menuItem
protected void datagridview1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
ContextMenuStrip my_menu = new ContextMenuStrip();
int position_xy_mouse_row = dataGridView1.HitTest(e.X, e.Y).RowIndex;
if (position_xy_mouse_row >= 0)
{
my_menu.Items.Add("Show Details").Name = "Details";
if ((SecurityLevel == "something" && dataGridView1.SelectedRows[0].Cells[8].Value.ToString() == "value1") || (SecurityLevel == "something" && dataGridView1.SelectedRows[0].Cells[8].Value.ToString() == "value2"))
{
my_menu.Items.Add("update").Name = "Update ";
if (dataGridView1.SelectedRows[0].Cells[8].Value.ToString() == "value1")
{
MenuItem updateStatus = new MenuItem("Update");
updateStatus.MenuItems.Add(new MenuItem("somevalue").Name = "somevalue");
updateStatus.MenuItems.Add(new MenuItem("someothervalue").Name = "someothervalue");
}
if (dataGridView1.SelectedRows[0].Cells[8].Value.ToString() == "value2")
{
MenuItem updateStatus = new MenuItem("Update");
updateStatus.MenuItems.Add(new MenuItem("someothervalue").Name = "someothervalue");
updateStatus.MenuItems.Add(new MenuItem("newvalue").Name = "newvalue");
}
}
}
my_menu.Show(dataGridView1, new Point(e.X, e.Y));
my_menu.ItemClicked += new ToolStripItemClickedEventHandler(my_menu_ItemClicked);
}
}
but I can only see 2 menuitems on my menu which are Show Details and Update, I can't see the sub menu for update.
To add sub-menu items, you need to cast the desired item to a ToolStripMenuItem, then add the sub-items to the DropDownItems property - hooking up the event handler in the constructor. You can create each with a unique event handler or just a single handler with logic checks on the ToolStripMenuItem.Name:
if (position_xy_mouse_row >= 0)
{
my_menu.Items.Add("Show Details").Name = "Details";
if ((SecurityLevel == "something" && dataGridView1.SelectedRows[0].Cells[8].Value.ToString() == "value1") || (SecurityLevel == "something" && dataGridView1.SelectedRows[0].Cells[8].Value.ToString() == "value2"))
{
my_menu.Items.Add("update").Name = "Update";
if (dataGridView1.SelectedRows[0].Cells[8].Value.ToString() == "value1")
{
(my_menu.Items["Update"] as ToolStripMenuItem).DropDownItems.Add("somevalue", null, new EventHandler(this.SubItem_Click)).Name = "somevalue";
(my_menu.Items["Update"] as ToolStripMenuItem).DropDownItems.Add("someothervalue", null, new EventHandler(this.SubItem_Click)).Name = "someothervalue";
}
if (dataGridView1.SelectedRows[0].Cells[8].Value.ToString() == "value2")
{
(my_menu.Items["Update"] as ToolStripMenuItem).DropDownItems.Add("someothervalue", null, new EventHandler(SubItem_Click)).Name = "someothervalue";
(my_menu.Items["Update"] as ToolStripMenuItem).DropDownItems.Add("newvalue", null, new EventHandler(SubItem_Click)).Name = "newvalue";
}
}
}
my_menu.Show(dataGridView1, new Point(e.X, e.Y));
my_menu.ItemClicked += new ToolStripItemClickedEventHandler(MenuItem_Clicked);
Then your handlers:
private void MenuItem_Clicked(object sender, ToolStripItemClickedEventArgs e)
{
Console.WriteLine("Clicked {0}", e.ClickedItem.Name);
}
private void SubItem_Click(object sender, EventArgs e)
{
Console.WriteLine("Clicked {0}", (sender as ToolStripMenuItem).Name);
}

WPF Datagrid multiple selection is lost on drag

I'm trying to drag multiple selected rows from one DataGrid to another. For this I am using a handler for the MouseMove event like this:
private void Distribution_MouseMove(object sender, MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.LeftButton == MouseButtonState.Pressed)
{
var dg = sender as DataGrid;
if (dg == null) return;
if (dg.SelectedItems.Count == 0) return;
Point p = e.GetPosition(this);
HitTestResult result = VisualTreeHelper.HitTest(this, p);
var obj = result.VisualHit;
while (VisualTreeHelper.GetParent(obj) != null && !(obj is DataGridRow))
{
obj = VisualTreeHelper.GetParent(obj);
}
if (obj == null) return;
var row = obj as DataGridRow;
if (row == null) return;
if (dg.SelectedItems.Contains(row.DataContext))
{
e.Handled = true;
DataObject data = new DataObject();
data.SetData("registries", dg.SelectedItems.Cast<Registry>().ToList());
DragDrop.DoDragDrop(this, data, DragDropEffects.Move);
}
}
}
The problem is, having multiple rows selected, clicking to drag and drop makes the clicked row become the only selected row and only that row gets moved.
How can I keep the multiple selection or what other event should I use to start dragging before the selection is changed?
I found the answer thanks to this post.
First I added a PreviewMouseLeftButtonDown handler that would add all the selected items to another list:
private List<Registro> _selected = new List<Registry>();
private void Distribution_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var dg = sender as DataGrid;
if (dg == null) return;
_selected.Clear();
_selected.AddRange(dg.SelectedItems.Cast<Registry>());
}
And then on the MouseMove handler added the following after e.Handled = true; and before creating the DataObject:
foreach (var registry in _selected)
{
if (!dg.SelectedItems.Contains(registry))
{
dg.SelectedItems.Add(registry);
}
}
It shows visibly the elements being deselected and selected again in the grid, but it works as expected.

Change visibility buttons in RepositoryItemButtonEdit by click

I have gridView with 3 columns. One column has repositoryItempictureEdit with 4 EditorButtons
this.repActionsBtn.Buttons.AddRange(new DevExpress.XtraEditors.Controls.EditorButton[] {
new DevExpress.XtraEditors.Controls.EditorButton(),
new DevExpress.XtraEditors.Controls.EditorButton(),
new DevExpress.XtraEditors.Controls.EditorButton(),
new DevExpress.XtraEditors.Controls.EditorButton()});
And i have a buttonClick event handler
private void repActionsBtn_ButtonClick(object sender, DevExpress.XtraEditors.Controls.ButtonPressedEventArgs e)
{
ButtonEdit editor = sender as ButtonEdit;
if (editor != null)
{
object obj = this.mainView.GetFocusedRow();
int id = GetValueFromAnonymousType<int>(obj, "ID");
//undo
if (e.Button == editor.Properties.Buttons[0])
{
_ignoredIds.Remove(id);
}
//delete
else if (e.Button == editor.Properties.Buttons[1])
{
//HERE i want change visibility buttons
e.Button.Visibility = false;
_ignoredIds.Add(id);
}
//edit
else if (e.Button == editor.Properties.Buttons[2])
{
_storedIds.Clear();
_storedIds.Add(id);
this.DialogResult = System.Windows.Forms.DialogResult.Retry;
}
//save
else if (e.Button == editor.Properties.Buttons[3])
{
//save
_storedIds.Remove(id);
}
mainView.RefreshRow(this.mainView.FocusedRowHandle);
}
}
But fires redraw and i get default repositoryItemButtonEdit with buttons is visible.
How i can change visibility(or property Enabled) of EditorButtons by user actions. (For each row)?
Devexpress support give me a solution. Here you can find the solution and download test project.

How can I add a context menu to a ListBoxItem?

I have a ListBox and I want to add a context menu to each item in the list. I've seen the "solution" to have the right click select an item and suppress the context menu if on white space, but this solution feels dirty.
Does anyone know a better way?
Just to elaborate a little further to what Frans has said...Even though the ListBox owns the ContextMenuStrip, you can still customize the items in the menu strip at the time it's opening. Thus customizing it's contents based on the mouse position within the listbox.
The example below selects the item in the listbox based on a right mouse click and then customizes a context menu strip based on the item the user right-clicked on. This is a simple example but should get you going: Add a listbox to a form and add this code:
#region Private Members
private ContextMenuStrip listboxContextMenu;
#endregion
private void Form1_Load( object sender, EventArgs e )
{
//assign a contextmenustrip
listboxContextMenu = new ContextMenuStrip();
listboxContextMenu.Opening +=new CancelEventHandler(listboxContextMenu_Opening);
listBox1.ContextMenuStrip = listboxContextMenu;
//load a listbox
for ( int i = 0; i < 100; i++ )
{
listBox1.Items.Add( "Item: " + i );
}
}
private void listBox1_MouseDown( object sender, MouseEventArgs e )
{
if ( e.Button == MouseButtons.Right )
{
//select the item under the mouse pointer
listBox1.SelectedIndex = listBox1.IndexFromPoint( e.Location );
if ( listBox1.SelectedIndex != -1)
{
listboxContextMenu.Show();
}
}
}
private void listboxContextMenu_Opening( object sender, CancelEventArgs e )
{
//clear the menu and add custom items
listboxContextMenu.Items.Clear();
listboxContextMenu.Items.Add( string.Format( "Edit - {0}", listBox1.SelectedItem.ToString() ) );
}
Hope that help.
This way the menu will pop up next to the mouse
private string _selectedMenuItem;
private readonly ContextMenuStrip collectionRoundMenuStrip;
public Form1()
{
var toolStripMenuItem1 = new ToolStripMenuItem {Text = "Copy CR Name"};
toolStripMenuItem1.Click += toolStripMenuItem1_Click;
var toolStripMenuItem2 = new ToolStripMenuItem {Text = "Get information on CR"};
toolStripMenuItem2.Click += toolStripMenuItem2_Click;
collectionRoundMenuStrip = new ContextMenuStrip();
collectionRoundMenuStrip.Items.AddRange(new ToolStripItem[] {toolStripMenuItem1, toolStripMenuItem2 });
listBoxCollectionRounds.MouseDown += listBoxCollectionRounds_MouseDown;
}
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
var info = GetInfoByName(_selectedMenuItem);
MessageBox.Show(info.Name + Environment.NewLine + info.Date);
}
private void toolStripMenuItem1_Click(object sender, EventArgs e)
{
Clipboard.SetText(_selectedMenuItem);
}
private void myListBox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Right) return;
var index = myListBox.IndexFromPoint(e.Location);
if (index != ListBox.NoMatches)
{
_selectedMenuItem = listBoxCollectionRounds.Items[index].ToString();
collectionRoundMenuStrip.Show(Cursor.Position);
collectionRoundMenuStrip.Visible = true;
}
else
{
collectionRoundMenuStrip.Visible = false;
}
}
There's no other way: the context menu isn't owned by the item in the listbox but by the listbox itself. It's similar to the treeview control which also owns the context menu instead of the treenode. So whenever an item in the listbox is selected, set the context menu of the listbox according to the selected item.
And Here it is My Solution :
listBox_Usernames.ContextMenuStrip = contextMenuStripRemove;
listBox_Usernames.MouseUp += new MouseEventHandler(listBox_Usernames_MouseUp);
void listBox_Usernames_MouseUp(object sender, MouseEventArgs e)
{
int index = listBox_Usernames.IndexFromPoint(e.Location);
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
if (index != ListBox.NoMatches)
{
if (listBox_Usernames.SelectedIndex == index)
{
listBox_Usernames.ContextMenuStrip.Visible = true;
}
else
{
listBox_Usernames.ContextMenuStrip.Visible = false;
}
}
else
{
listBox_Usernames.ContextMenuStrip.Visible = false;
}
}
else
{
listBox_Usernames.ContextMenuStrip.Visible = false;
}
}
In XAML it shows like this:
<ListBox>
<ListBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Add User..."/>
<MenuItem Header="Edit..."/>
<MenuItem Header="Disable"/>
</ContextMenu>
</ListBox.ContextMenu>
</ListBox>
In one line of code (more for binding):
var datasource = new BindingList<string>( new List<string>( new string[] { "item1" } ) );
listbox.DataSource = datasource ;
listbox.ContextMenu = new ContextMenu(
new MenuItem[] {
new MenuItem("Delete",
new EventHandler( (s,ev) =>
datasource.Remove(listbox.SelectedItem.ToString())
)
)
});
private void buttonAdd_Click(object sender, EventArgs e)
{
datasource.Add( textBox.Text );
}
If its just a question of enabling or disabling context menu items, it might be more efficient to only do it when the context menu is launched rather than every time the list box selection changes:
myListBox.ContextMenu.Popup += new EventHandler(myContextPopupHandler);
private void myContextPopupHandler(Object sender, System.EventArgs e)
{
if (SelectedItem != null)
{
ContextMenu.MenuItems[1].Enabled = true;
ContextMenu.MenuItems[2].Enabled = true;
}
else
{
ContextMenu.MenuItems[1].Enabled = false;
ContextMenu.MenuItems[2].Enabled = false;
}
}
this one is best...
using System.Windows.Forms;
ContextMenuStrip menu;
this.menu.Items.AddRange(new ToolStripItem[] { this.menuItem });
this.listBox.MouseUp += new MouseEventHandler(this.mouse_RightClick);
private void mouse_RightClick(object sender, MouseEventArgs e)
{
int index = this.listBox.IndexFromPoint(e.Location);
if (index != ListBox.NoMatches)
{
menu.Visible = true;
}
else
{
menu.Visible = false;
}
}
//Create and Initialize the contextMenuStrip component
contextMenuStrip_ListaAulas = new ContextMenuStrip();
//Adding an Item
contextMenuStrip_ListaAulas.Items.Add("Modificar");
//Binding the contextMenuStrip with the ListBox
listBox_Aulas.ContextMenuStrip = contextMenuStrip_ListaAulas;
//The solution below
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
//select the item under the mouse pointer
listBox_Aulas.SelectedIndex = listBox_Aulas.IndexFromPoint(e.Location);
//if the selected index is an item, binding the context MenuStrip with the listBox
if (listBox_Aulas.SelectedIndex != -1)
{
listBox_Aulas.ContextMenuStrip = contextMenuStrip_ListaAulas;
}
//else, untie the contextMenuStrip to the listBox
else
{
listBox_Aulas.ContextMenuStrip = null;
}
}
I do like this, this works great and fast for me.
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
if (Listbox.SelectedItem == null)
e.Cancel = true;
}

Categories