if(e.Button == MouseButtons.Right)
{
string signatureDate = dataGridView3.CurrentRow.Cells[8].Value.ToString();
// MessageBox.Show(signatureDate);
if(signatureDate.Length > 5)
{
contextMenuStrip1.Items[0].Visible = false;
contextMenuStrip1.Items[1].Visible = true;
}else
{
contextMenuStrip1.Items[0].Visible = true;
contextMenuStrip1.Items[1].Visible = false;
}
}
I have a context strip menu that is working in my datagridview. And I selected it as Row Context Strip Menu.
What I am trying to do is to get if selected row of datagridview and control signature column is null or not. If it has signature date I want to hide or unhide "Sign" and if it doesn't have signature date hide "Unsign" item on context menu strip.
You can see in picture I enclosed.Context menu Strip
EDIT: Name of the event is MouseDown.
EDIT 2: With editing this code I can get columns data and show them on messageBox. But I can not use those data as a condition. Therefore it is not working. For example, when I select a row that is without "Signature Date" and show it on messageBox, it is working. But when I use Signature Date data as a condition It is not working. I know it is so strange and too easy to overcome but I coundn't because of that I didn't catch anything.
EDIT 3: Event
EDIT 4 (SOLVED) : I created to Context Strip Menu and specify no one of them
as Context strip Menu of Datagridview.
With Datagridview_MouseDown event, I am getting Signature Date column data and check if it is null/empty or not. If it is null/empty I specify first Context Menu strip as Context Strip Menu of Datagridview or not I do revise. I figured out the solution in this way :)
I think your problem is in the instance of context menu strip use this one see if it helps.
if(e.Button == MouseButtons.Right)
{
string signatureDate = dataGridView3.CurrentRow.Cells[8].Value.ToString();
// MessageBox.Show(signatureDate);
if(signatureDate.Length > 5)
{
dataGridView3.ContextMenu.Items[0].Visible = false;
dataGridView3.ContextMenu.Items[1].Visible = true;
}else
{
dataGridView3.ContextMenu.Items[0].Visible = true;
dataGridView3.ContextMenu.Items[1].Visible = false;
}
}
Probably your event is not firing.
Instead of using mouse down you could also use the Opening event of the contextMenuStrip
This should solve your problem
private void Form1_Load(object sender, EventArgs e)
{
dataGridView3.ContextMenu = contextMenuStrip1;
contextMenuStrip1.Opening += contextMenuStrip1_Opening;
}
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
string signatureDate = dataGridView3.CurrentRow.Cells[8].Value.ToString();
// MessageBox.Show(signatureDate);
if (signatureDate.Length > 5)
{
contextMenuStrip1.Items[0].Visible = false;
contextMenuStrip1.Items[1].Visible = true;
}
else
{
contextMenuStrip1.Items[0].Visible = true;
contextMenuStrip1.Items[1].Visible = false;
}
}
Related
I have created more than 5 GRID for which there are a few column that are empty/zero. These are numbered as example 1,2,3...
I have already implemented that I can select and deselect single cells for this columns.
Now my question is (and I am still very inexperienced with Infragistics)
How do I get the Name Property of my grid just by clicking on it?
Some parameters I could read out like the cells.index or the rows.index, but I want to know for another method the exact Name Property in which just the cell was clicked.
Via the event handler I let all my grids into the cells click method
private void GRD_LIST_Grid_ClickCell(object sender, Infragistics.Win.UltraWinGrid.ClickCellEventArgs e)
{
if (e.Cell.Column.ToString().Contains("BAHN") && e.Cell.Tag == "1") //1-5 Column have the name "BAHN", the Tag is for an flag if the cell is clicked before
{
e.Cell.Selected = false;
e.Cell.Tag = null;
SetPrio(e.Cell.Row.Index, e.Cell.Column.Index);
}
else if (e.Cell.Column.ToString().Contains("BAHN") && e.Cell.Tag == null)
{
SetPrio(e.Cell.Row.Index, e.Cell.Column.Index);
e.Cell.Tag = "1";
}
//when the cell is click show the cell in green
if (e.Cell.Tag == "1")
{
e.Cell.Row.Cells[e.Cell.Column.ToString()].Appearance.BackColor = System.Drawing.Color.Green;
}
else if (e.Cell.Tag == null)
{
e.Cell.Row.Cells[e.Cell.Column.ToString()].Appearance.BackColor = System.Drawing.Color.FromArgb(234,244,243);
}
ClearSelectedRow(); //a Method where i set all grids in an array and clear all rows because i dont know which grid i am
}
When the ClickCell event occurs the first parameter of the event handler is sender and in this case it's the Infragistics.Win.UltraWinGrid.UltraGrid source. Therefore, it is possible to get the grid name like in code below:
private void GRD_LIST_Grid_ClickCell(object sender, Infragistics.Win.UltraWinGrid.ClickCellEventArgs e)
{
if (sender is Infragistics.Win.UltraWinGrid.UltraGrid ugrid)
{
System.Diagnostics.Debug.WriteLine($"The ClickCell event is raised by '{ugrid.Name}'");
}
}
I would like to disable 2 buttons at one click, without specifying these buttons. I have ~150 buttons on my form, and I dont want to write a function for all of them.
I have a function something like this, to disable a button I click on.
public void disableButton(object sender, EventArgs e)
{
if (((Button)sender).Enabled == true)
{
((Button)sender).Enabled = false;
((Button)sender).BackColor = Color.Red;
}
}
So basically, when I call this function, I would like to disable THIS button, and a button next to it. (Eg. button1 and button2)
Considering the button should be added in the control in a specific order, so that when you will get all the buttons based on your requirement you can disable the immediate next button to the current button, Kindly refer to below code:
public void disableButton(object sender, EventArgs e)
{
var selectedButton = ((Button)sender);
var allButtons = Controls.OfType<Button>().ToList();
var currentButtonIndex = allButtons.Select((s, i) => new { button = s, index = i }).Single(si => si.button.Name == selectedButton.Name).index;
if (allButtons[currentButtonIndex + 1].Enabled == true)
{
allButtons[currentButtonIndex + 1].Enabled = false;
allButtons[currentButtonIndex + 1].BackColor = Color.Red;
}
}
To get list of all buttons in your form Controls.OfType<Button>().ToList(), next step is to get the index of current button. Once you get the index the increment it with 1 and you will get the reference of the next button
for safer implementation just check if it is not the last button in that case choose the first button, refer below code:
currentButtonIndex = currentButtonIndex + 1 >= allButtons.Count() ? 0 : currentButtonIndex;
Suppose you are not able to figure out the ordering of the buttons, but the next button should be based on TabStop, based on TabStop you can better find the next button, refer below code
var allButtons = Controls.OfType<Button>().OrderBy(o => o.TabStop).ToList();
var currentButtonIndex = allButtons.Select((s, i) => new { button = s, index = i }).Single(si => si.button.Name == selectedButton.Name).index;
var toDisableButton = allButtons[currentButtonIndex + 1];
Controls.OfType<Button>().Single(si => si.Name == toDisableButton.Name).Enabled = false;
Create a collection of pairs, where pair: (name_of_btn_1, name_of_btn_2).
This can be an IDictionary<string, string>.
Inside the click event handler, get the associated button name using the dictionary. Then, you can do this.Controls.Find() to get the associated button by name and disable it.
I have a c# winform with tabControl (it has 5 Tabs), textboxes, datetimepicker and checkboxes, connected via Entity Framework to a table.
All my checkboxes have their property Checked set to False, CheckState set to Unchecked and ThreeState set to False.
When I'm adding a new record, my checkboxes encounter a very strange behaviour. At adding a new record, my program calls a subroutine called EmptyCheckBoxes to make sure, that they are all set to false and their texts are set to "Ne". So far so good --> they are set to false and texts are correct(see image1).
Here are 2 scenarios with my problem:
1.
I click one checkbox to make him checked (set to true and set its text to "Da" --> look at Ponedeljek on image2). Till here, everything went as planned.
But, if I use my mouse and try click other checkbox (look at Torek on image3), this checkbox remains unchecked and all other checkboxes on my form have become grayed and checked!
2.
At adding a new record checkboxes are set to false and texts are correct(see image1). But, this time I'm not going to touch my checkboxes, I just click into my datetimepicker and then into some other textbox. Bam!
All checkboxes on my form have become grayed and checked!
How can this be, if their ThreeState property is set to False?
This is really annoying and I'm totaly lost, where to look to find the cause of this problem. Because, if I save this new record, all checkboxes lose their gray color and stay checked with texts "Ne" (values true are saved into table!).
All checkboxes have this code (this is from one of them):
private void checkBox49_Click(object sender, EventArgs e)
{
if (checkBox49.Checked == true)
{
checkBox49.Text = "Da";
}
else
{
checkBox49.Text = "Ne";
}
}
private void checkBox49_CheckedChanged(object sender, EventArgs e)
{
if (checkBox49.Checked == true)
{
checkBox49.Text = "Da";
}
else
{
checkBox49.Text = "Ne";
}
}
This is a code for setting checkboxes to false and texts to "Ne":
private void EmptyCheckBoxes()
{
TabPage tabPage1 = tabControl1.TabPages[0];
TabPage tabPage2 = tabControl1.TabPages[1];
TabPage tabPage3 = tabControl1.TabPages[2];
TabPage tabPage4 = tabControl1.TabPages[3];
TabPage tabPage5 = tabControl1.TabPages[4];
tabControl1.SelectedTab = tabPage1;
UncheckCheckBoxes(tabPage1);
tabControl1.SelectedTab = tabPage2;
UncheckCheckBoxes(tabPage2);
tabControl1.SelectedTab = tabPage3;
UncheckCheckBoxes(tabPage3);
tabControl1.SelectedTab = tabPage4;
UncheckCheckBoxes(tabPage4);
tabControl1.SelectedTab = tabPage5;
UncheckCheckBoxes(tabPage5);
}
private void UncheckCheckBoxes(Control ctrl)
{
CheckBox chkBox = ctrl as CheckBox;
if (chkBox == null)
{
foreach (Control child in ctrl.Controls)
{
UncheckCheckBoxes(child);
}
}
else
{
chkBox.Checked = false;
chkBox.Text = "Ne";
}
}
Thank you for any hint, clue or solution to this problem.
Vladimir
Fabio, you were right about _Click eventhandler. But it did not solve my problem.
My problem are causing groupboxes on my winform. Why, I don't know.
This is my workaround for CheckStateChanged event that works like charm:
private void My_checkBox_CheckStateChanged(object sender, EventArgs e)
{
if (_addnew == true)
{
CheckBox my_cb = (CheckBox)sender;
if ((my_cb.CheckState == CheckState.Indeterminate) && (my_cb.Text == "Da"))
{
my_cb.Checked = false;
my_cb.Text = "Ne";
}
}
}
I'm creating a ToolStripMenu shown below that is supposed to allow the user to interact with the items "XML" and "Non XML" as though they are regular check boxes on a form. However, when one item is checked/unchecked the menu closes. How can I allow an item to be checked/unchecked without closing the menu? Or is there a different standard method of achieving the same behavior?
So what I want is to be able to click on "Non XML", show a check box and leave the menu open.
The idea is that the last menu item will be "Done" and when it's clicked the "G2S" sub items will remain open but the "Display" sub items ( XML, Non XML ) will close.
Any ideas?
Note: I am aware that this is likely not the best user interface design. I'd like to know however how this could be accomplished just to gain some technical knowledge about handling menus.
Interesting concept is described in this thread on Stackoverflow:
Here is the essence of the accepted answer:
ParentMenu.DropDown.AutoClose = false;
It does exactly what you are asking for - prevent menu from closing when subitem is clicked.
Here's a useful extension that requires user to click outside of menu item + dropdowns to close.
public static void KeepOpenOnDropdownCheck (this ToolStripMenuItem ctl)
{
foreach (var item in ctl.DropDownItems.OfType<ToolStripMenuItem>())
{
item.MouseEnter += (o, e) => ctl.DropDown.AutoClose = false;
item.MouseLeave += (o, e) => ctl.DropDown.AutoClose = true;
}
}
Posted in case somebody finds it helpful.
Instead of trying to do exactly what I had originally intended, I've come up with the following:
1- Use a ContextMenuStrip
2- When the user clicks on the ToolStripMenu item I display the ContextMenuStrip at a location near the menu item as shown below: ( note the positioning still needs adjusting )
To get this working I build the ContextMenuStrip in code at run-time so that the items in the ContextMenuStrip can be build dynamically based on the situation.
Code snippets:
Show the ContextMenuStrip when the menu item is clicked:
private void filterToolStripMenuItem_Click(object sender, EventArgs e)
{
contextMenuStrip1.Show(this, 180, 20);
}
Build the ContextMenuStrip:
if (protInfo.Name == "QCOM" )
{
BroadCast = new CheckBox();
BroadCast.Text = "Date/Time Broadcast";
BroadCast.Checked = FlagSet(CurrentFilter, (Byte)Filter.DateTimeBC);
ToolStripControlHost Ch1 = new ToolStripControlHost(BroadCast);
GenPoll = new CheckBox();
GenPoll.Text = "Status Poll";
GenPoll.Checked = FlagSet(CurrentFilter, (Byte)Filter.GenStatusPoll);
ToolStripControlHost Ch2 = new ToolStripControlHost(GenPoll);
GenPollResp = new CheckBox();
GenPollResp.Text = "Status Poll Response";
GenPollResp.Checked = FlagSet(CurrentFilter, (Byte)Filter.GenStatusResponse);
ToolStripControlHost Ch3 = new ToolStripControlHost(GenPollResp);
Button btnDone = new Button();
btnDone.Text = "Done";
ToolStripControlHost Ch4 = new ToolStripControlHost(btnDone);
btnDone.Click += new EventHandler(btnDone_Click);
contextMenuStrip1.Items.Clear();
contextMenuStrip1.Items.Add(Ch1);
contextMenuStrip1.Items.Add(Ch2);
contextMenuStrip1.Items.Add(Ch3);
contextMenuStrip1.Items.Add(Ch4);
contextMenuStrip1.Enabled = true;
filterToolStripMenuItem.Enabled = true;
}
else
{
filterToolStripMenuItem.Enabled = false;
}
This may not be the best user interface design, but it seems to work.
The original solution will work with the use of mouse events.
On mouse enter event:
parent.dropdown.autoclose = false;
on mouse leave event:
parent.dropdown.autoclose = true;
The only catch is if the user access the menu items by other means than a mouse.
I used a combination of Neolisk's and Chimera's answers to allow deletion of multiple leaf items from a treeview. My solution is below
Note: the following Items created at design time are used:
TreePromotions (TreeView)
menuVendorSection (Context Menu Strip)
removeMultipleItemsToolStripMenuItem (DropDown of menuVendorSection)
private void removeMultipleItemsToolStripMenuItem_MouseHover(object sender, EventArgs e)
{
removeMultipleItemsToolStripMenuItem.DropDownItems.Clear();
ToolStripMenuItem detailMenuItem;
TreeNode vendorSectionNode = treePromotions.SelectedNode;
for (int vsn = 0; vsn < vendorSectionNode.Nodes.Count; vsn++)
{
//add checkbox item
detailMenuItem = new ToolStripMenuItem(vendorSectionNode.Nodes[vsn].Text);
detailMenuItem.Tag = vendorSectionNode.Nodes[vsn].Tag;
detailMenuItem.CheckOnClick = true;
removeMultipleItemsToolStripMenuItem.DropDownItems.Add(detailMenuItem);
}
//add action buttons
Button buttonDeleteMultiple = new Button();
buttonDeleteMultiple.Text = "Remove Checked Items";
ToolStripControlHost buttonHost = new ToolStripControlHost(buttonDeleteMultiple);
buttonDeleteMultiple.Click += new EventHandler(buttonDeleteMultiple_Click);
removeMultipleItemsToolStripMenuItem.DropDownItems.Add(buttonHost);
Button buttonCancelMultipleDelete = new Button();
buttonCancelMultipleDelete.Text = "CANCEL";
buttonHost = new ToolStripControlHost(buttonCancelMultipleDelete);
buttonCancelMultipleDelete.Click += new EventHandler(buttonCancelMultipleDelete_Click);
removeMultipleItemsToolStripMenuItem.DropDownItems.Add(buttonHost);
removeMultipleItemsToolStripMenuItem.DropDown.AutoClose = false;
menuVendorSection.AutoClose = false;
}
private void buttonDeleteMultiple_Click(object sender, EventArgs e)
{
//delete items
for (int dmi = 0; dmi < removeAllItemsToolStripMenuItem.DropDownItems.Count - 2; dmi++) //do not include buttons
{
((Detail)removeAllItemsToolStripMenuItem.DropDownItems[dmi].Tag).Delete(); //deletes item from database
}
//rebuild leaf
treePromotions.SelectedNode.Nodes.Clear();
addItemNodes(treePromotions.SelectedNode); //builds leaf nodes from database
//close menus
removeMultipleItemsToolStripMenuItem.DropDown.Close();
menuVendorSection.AutoClose = true;
menuVendorSection.Close();
}
private void buttonCancelMultipleDelete_Click(object sender, EventArgs e)
{
//just close menus
removeMultipleItemsToolStripMenuItem.DropDown.Close();
menuVendorSection.AutoClose = true;
menuVendorSection.Close();
}
If someone is still interested, here is a vb solution:
1) For the parent tool strip menu item, add the following handler in the form's constructor:
AddHandler ParentTSMI.DropDown.Closing, AddressOf onDropDownClosing
2) The handler:
Private Sub onDropDownClosing(sender As Object, e As ToolStripDropDownClosingEventArgs)
If e.CloseReason = ToolStripDropDownCloseReason.ItemClicked Then
e.Cancel = True
End If
End Sub
That's it all.
Don't forget to remove the handler (RemoveHandler) when you close the form.
I'm trying to update this DataGridView object such that if a value == "bob" there will be a button in a column next to its name, otherwise I don't want any button to appear.
DataGridViewTextBoxColumn valueColumn = new DataGridViewTextBoxColumn();
DataGridViewButtonColumn buttonColumn = new DataGridViewButtonColumn();
buttonColumn.ReadOnly = true;
buttonColumn.Visible = false;
this.dgv.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
valueColumn,
buttonColumn,
});
//elsewhere...
if(value == "bob")
{
Button button = new Button()
{
Text = "null",
};
index = dgv.Rows.Add(value, button);
DataGridViewButtonCell buttonCell = dgv.Rows[index].Cells[2] as DataGridViewButtonCell;
buttonCell.Visible = true;
}
else
{
dgv.Rows.Add(value);
}
But, since I can't set Visible on a cell, this doesn't work. Is there a way to add a button to only the rows were Value == "bob"?
Here is a neat little hack that I've used before to accomplish this:
Instead of using a DataGridViewButtonColumn, use the DataGridViewTextBoxColumn and add a DataGridViewButtonCell where appropriate.
e.g.
private void button1_Click(object sender, EventArgs e)
{
// Iterate through each of the rows.
for (int i = 0; i < dgv.RowCount - 1; i++)
{
if (dgv.Rows[i].Cells[0].Value.ToString() == "bob")
{
// Here is the trick.
var btnCell = new DataGridViewButtonCell();
dgv.Rows[i].Cells[1] = btnCell;
}
}
}
In the example above, I have two DataGridViewTextBoxColumns and iterate through each of the rows on a button click event. I check the first column to see if it contains "bob" and if it does, I add a button in the column next to it. You can use this trick however you want (i.e. button clicks, RowsAdded event, CellEndEdit event, etc.). Experiment in different ways. Hope this helps someone!
There are two possibilities here, one ugly and one from MSDN.
The Ugly: Add a button to your DGV at runtime
Do the following:
- Add an unbound DataGridViewTextBoxColumn to your DGV. Note it's index value in your DGV; this is where you'll put your button.
- Use your DGV's CellFormatting event like so:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e) {
if (e.ColumnIndex == 0) { // Assumes column 0 has the data that determines if a button should be displayed.
if (e.Value.ToString() == "bob") { // Test if a button should be displayed on row.
// Create a Button and add it to our DGV.
Button cellButton = new Button();
// Do something to identify which row's button was clicked. Here I'm just storing the row index.
cellButton.Tag = e.RowIndex;
cellButton.Text = "Hello bob";
cellButton.Click += new EventHandler(cellButton_Click);
dataGridView1.Controls.Add(cellButton);
// Your ugly button column is shown here as having an index value of 3.
Rectangle cell = this.dataGridView1.GetCellDisplayRectangle(3, e.RowIndex, true);
cellButton.Location = cell.Location;
}
}
}
When a user clicks the button the cellButton_Click event will fire. Here's some test code:
void cellButton_Click(object sender, EventArgs e) {
Console.WriteLine("Hello from row: {0}", ((Button) sender).Tag);
}
As you can see this isn't very refined. I based it on an even uglier sample I found. I'm sure you can modify it to suit your needs.
From MSDN: Roll your own (extend) DataGridViewButtonColumn that conditionally displays a disabled button.
For this option see How to: Disable Buttons in a Button Column in the Windows Forms DataGridView Control
Of course this option doesn't actually remove any buttons, only conditionally disables them. For your application however, this might be better.
You can handle cell painting on cell painting event:
private void dgv_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if(e.RowIndex>=0 && e.ColumnIndex == indexOfButtonColumn && value[e.RowIndex] != "bob")
{
e.Paint(e.ClipBounds, DataGridViewPaintParts.All & ~DataGridViewPaintParts.ContentForeground & ~DataGridViewPaintParts.ContentBackground);
e.Handled = true;
}
}