Host a DataGridView on a ContextMenuStrip using ToolStripControlHost
-
Friday, April 27, 2012 10:28 PM
I'm trying to show a small DataGridView in my ContextMenuStrip that I have built. The DataGridView will show a unique list of values in a DataGridViewTextboxColumn "Sample ID" when its column header is right-clicked. I can get the unique values just fine, but I'm having trouble displaying the small DataGridView in the ContextMenuStrip. It currently looks like this.
Notice, there is no data in the DataGridView. I have confirmed that the DataGridView.DataSource has several rows in it, yet the DataGridView shows nothing. Plus, I need to increase the size of my DataGridView, thus increasing the size of the ContextMenuStrip to show the DataGridView.
Here is my code (sorry if its too much, just wanted to make sure you see the whole picture):
Public Class ContextMenu_Column_String Inherits ContextMenuStrip Private dvs As DataGridViewSettings Private dgv As DataGridView Private ht As DataGridView.HitTestInfo Private dfs As DataGridViewFilterAndSorter Public Sub New(ByVal sender As DataGridViewSettings, ByVal e As System.Windows.Forms.MouseEventArgs) Me.dvs = CType(sender, DataGridViewSettings) Me.dgv = Me.dvs.DataGridView Me.ht = Me.dgv.HitTest(e.X, e.Y) Me.dfs = Me.dvs.DataGridViewFilterAndSorter Dim dtUniqueValues As DataTable = Me.dfs.MasterDataTable.Copy.AsDataView.ToTable(True, Me.dgv.Columns(ht.ColumnIndex).DataPropertyName) dtUniqueValues.Columns.Add("Select", Type.GetType("System.Boolean")) Dim dv As DataView = dtUniqueValues.AsDataView dv.Sort = Me.dgv.Columns(ht.ColumnIndex).DataPropertyName Dim chk As New DataGridViewCheckBoxColumn With chk .Name = "Select" .Width = 25 .DataPropertyName = "booSelect" End With Dim tex As New DataGridViewTextBoxColumn With tex .Name = "Values" .Width = 100 .DataPropertyName = Me.dgv.Columns(ht.ColumnIndex).DataPropertyName End With Dim dgvUnique As New DataGridView dgvUnique.Columns.Add(chk) dgvUnique.Columns.Add(tex) dgvUnique.Width = 125 dgvUnique.CellBorderStyle = DataGridViewCellBorderStyle.None dgvUnique.ColumnHeadersVisible = False dgvUnique.AutoGenerateColumns = False dgvUnique.DataSource = dtUniqueValues Dim CMS As New ContextMenuStrip Dim CM_SubMenu As New ToolStripMenuItem() Dim IC As New IconConverter With CMS.Items .Add(New ToolStripMenuItem("Copy", IC.ConvertTo(My.Resources.copy, GetType(Image)), New EventHandler(AddressOf Me.CopySelectedCells), "nmCopy")) .Add(New ToolStripSeparator) .Add(New ToolStripMenuItem("Sort A to Z", My.Resources.SortHS, New EventHandler(AddressOf Me.SortAZ), "nmSortAZ")) .Add(New ToolStripMenuItem("Sort Z to A", Nothing, New EventHandler(AddressOf Me.SortZA), "nmSortZA")) .Add(New ToolStripMenuItem("Save My Sortings", Nothing, New EventHandler(AddressOf Me.SaveMySortings))) .Add(New ToolStripSeparator) .Add(New ToolStripMenuItem("Fill Column With ...", Nothing, New EventHandler(AddressOf Me.FillColumnWith), "nmFillColumnWith")) .Add(New ToolStripSeparator) .Add(New ToolStripMenuItem("Hide Column", Nothing, New EventHandler(AddressOf Me.HideColumn))) .Add(New ToolStripMenuItem("Edit Column Settings", Nothing, New EventHandler(AddressOf Me.EditColumnSettings))) .Add(New ToolStripSeparator) With CM_SubMenu .Text = "Add Column Filter" .Name = "nmAddColumnFilter" '.Image = With .DropDownItems .Add("Equals ...", Nothing, New EventHandler(AddressOf Me.Equal)) .Add("Does Not Equal ...", Nothing, New EventHandler(AddressOf Me.NotEqual)) .Add("Begins With ...", Nothing, New EventHandler(AddressOf Me.BeginWith)) .Add("Does Not Begin With ...", Nothing, New EventHandler(AddressOf Me.NotBeginWith)) .Add("Ends With ...", Nothing, New EventHandler(AddressOf Me.EndWith)) .Add("Does Not End With ...", Nothing, New EventHandler(AddressOf Me.NotEndWith)) .Add("Contains ...", Nothing, New EventHandler(AddressOf Me.Contain)) .Add("Does Not Contain ...", Nothing, New EventHandler(AddressOf Me.NotContains)) .Add("Between ...", Nothing, New EventHandler(AddressOf Me.Between)) .Add("Not Between ...", Nothing, New EventHandler(AddressOf Me.NotBetween)) .Add("Is Blank", Nothing, New EventHandler(AddressOf Me.Blank)) .Add("Is Not Blank", Nothing, New EventHandler(AddressOf Me.NotBlank)) End With .DisplayStyle = ToolStripItemDisplayStyle.Text End With .AddRange(New ToolStripItem() {CM_SubMenu}) .Add(New ToolStripControlHost(dgvUnique)) End With ' disable Fill Column With button if the column is Read-Only CMS.Items("nmFillColumnWith").Enabled = Not Me.dgv.Columns(Me.ht.ColumnIndex).ReadOnly CMS.Show(Me.dgv, e.X, e.Y) End Sub End Class
Anyone have a solution? I figure using the ToolStripControlHost class is the only way to do this, right?
Thanks,
Ryan
- Edited by Ryan0827 Monday, April 30, 2012 1:38 PM code update
All Replies
-
Monday, April 30, 2012 8:57 AM
Hi Ryan,
there is a lot of class didn't delare.
Pleasse post some correct code here.
Have a nice day.
Ghost,
Call me ghost for short, Thanks
To get the better answer, it should be a better question. -
Monday, April 30, 2012 10:15 AMModerator
Hi Ryan,
I did not use your original codes, but I think we can intialize the DataGridView's BindingContext property to make the databinding work.
Here are some testing codes to add a ToolStrip for a TextBox for your references:
Private Sub TextBox1_KeyDown(sender As System.Object, e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown If e.KeyData = Keys.F1 Then d1.BindingContext = New BindingContext d1.DataSource = MyTable Dim host As New ToolStripControlHost(d1) ContextMenuStrip1.Items.Clear() ContextMenuStrip1.Items.Add(host) ContextMenuStrip1.Show(TextBox1, 0, 27) End If End Sub
Good day!
Thanks
Michael Sun [MSFT]
MSDN Community Support | Feedback to us
- Proposed As Answer by CrazyGhost_Von Monday, April 30, 2012 1:45 PM
- Unproposed As Answer by Ryan0827 Monday, April 30, 2012 1:51 PM
-
Monday, April 30, 2012 1:37 PM
Ghost,
Thanks for the reply. What classes do you need to see? I believe all the relevant code is posted.
Ryan
-
Monday, April 30, 2012 1:45 PM
For example: DataGridViewSettings
But I think DataGridViewSettings class is not directly related to this issue. Right?
So you can make a simple code snippet to show your issue, rather than post such complex one.
Have a nice day.
Ghost,
Call me ghost for short, Thanks
To get the better answer, it should be a better question. -
Monday, April 30, 2012 2:07 PM
Ghost,
Correct, the DataGridViewSettings class is not directly related to this issue.
I shortened the code for better readability. To test my code you can setup a Form with a DataGridView on it. Then you can fill the DataGridView with whatever data you please. Then put this code in the DataGridView_MouseClick Event. Note: This code assumes you have a DataTable as the DataGridViews.DataSource.
Private Sub DataGridView1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles DataGridView1.MouseClick Dim dgv As DataGridView = CType(sender, DataGridView) Dim ht As DataGridView.HitTestInfo = dgv.HitTest(e.X, e.Y) Dim dt As DataTable = CType(dgv.DataSource, DataTable) Dim CMS As New ContextMenuStrip Dim TMH As New ToolStripControlHost(New DataGridView) ' create a table of unique values from the column that was right-clicked Dim dtUniqueValues As DataTable = dt.Copy.AsDataView.ToTable(True, dgv.Columns(ht.ColumnIndex).DataPropertyName) ' add a Boolean column to the DataTable dtUniqueValues.Columns.Add("booSelect", Type.GetType("System.Boolean"), False) ' sort the table Dim dv As New DataView(dtUniqueValues, Nothing, dgv.Columns(ht.ColumnIndex).DataPropertyName, DataViewRowState.CurrentRows) ' create a CheckBox column so the user can select values Dim chk As New DataGridViewCheckBoxColumn With chk .Name = "Select" .Width = 5 .DataPropertyName = "booSelect" End With ' create a TextBox column to show unique values Dim tex As New DataGridViewTextBoxColumn With tex .Name = "Values" .DataPropertyName = "vchAnalyteCode" End With ' create a binding source to ensure sychronization between DataGridView and DataTable Dim bs As New BindingSource bs.DataSource = dtUniqueValues ' set properties of the DataGridView that will be displayed in the ContextMenuStrip With CType(TMH.Control, DataGridView) .AutoGenerateColumns = False .Columns.Add(chk) .Columns(chk.Name).Width = 15 .Columns.Add(tex) .DataSource = bs .Width = 186 .Height = 200 .CellBorderStyle = DataGridViewCellBorderStyle.None .ColumnHeadersVisible = False .RowHeadersVisible = False End With ' add the ToolStripControlHost to the ContextMenuStrip to display our unique values CMS.Items.Add(TMH) CMS.Show(dgv, e.X, e.Y) End Sub
The goal is to display a DataGridView in a ContextMenuStrip. This DataGridView will contain a CheckBox column and TextBox column that displays all the unique values in the column that was right-clicked. I will use the values the user selects in the DataGridView as a filter. Does this help?
Thanks for sticking with this,
Ryan
-
Tuesday, May 01, 2012 2:18 AMModerator
Hi Ryan,
I think initializing the BindingContext as my last post suggested can help you solve the issue. I customized the codes as following:
Private Sub DataGridView1_MouseClick(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles DataGridView1.MouseClick Dim dgv As DataGridView = CType(sender, DataGridView) Dim ht As DataGridView.HitTestInfo = dgv.HitTest(e.X, e.Y) Dim dt As DataTable = CType(dgv.DataSource, DataTable) Dim CMS As New ContextMenuStrip Dim d1 As New DataGridView d1.BindingContext = New BindingContext Dim TMH As New ToolStripControlHost(d1) ' create a table of unique values from the column that was right-clicked Dim dtUniqueValues As DataTable = dt.Copy.AsDataView.ToTable(True, dgv.Columns(ht.ColumnIndex).DataPropertyName) ' add a Boolean column to the DataTable dtUniqueValues.Columns.Add("booSelect", Type.GetType("System.Boolean"), False) ' sort the table Dim dv As New DataView(dtUniqueValues, Nothing, dgv.Columns(ht.ColumnIndex).DataPropertyName, DataViewRowState.CurrentRows) ' create a CheckBox column so the user can select values Dim chk As New DataGridViewCheckBoxColumn With chk .Name = "Select" .Width = 5 .DataPropertyName = "booSelect" End With ' create a TextBox column to show unique values Dim tex As New DataGridViewTextBoxColumn With tex .Name = "Values" .DataPropertyName = "vchAnalyteCode" End With ' create a binding source to ensure sychronization between DataGridView and DataTable Dim bs As New BindingSource bs.DataSource = dtUniqueValues d1.DataSource = bs ' set properties of the DataGridView that will be displayed in the ContextMenuStrip With CType(TMH.Control, DataGridView) .AutoGenerateColumns = False .Columns.Add(chk) .Columns(chk.Name).Width = 15 .Columns.Add(tex) .DataSource = bs .Width = 186 .Height = 200 .CellBorderStyle = DataGridViewCellBorderStyle.None .ColumnHeadersVisible = False .RowHeadersVisible = False End With ' add the ToolStripControlHost to the ContextMenuStrip to display our unique values CMS.Items.Add(TMH) CMS.Show(dgv, e.X, e.Y) End SubPlease pay attention to the codes in bold.
Good day!
Thanks
Michael Sun [MSFT]
MSDN Community Support | Feedback to us
- Proposed As Answer by Michael Sun [MSFT]Microsoft Employee, Moderator Thursday, May 03, 2012 5:35 AM
- Marked As Answer by Ryan0827 Thursday, May 03, 2012 12:55 PM

