How to select a control programmatically in design mode - vb.net

Could someone please tell me how to select a control programmatically in design mode.
I tried to create a custom user control in VB.net that consists of two panels.
I want the whole user control to be easily selectable in design mode.
I have included the following sample and tried.
I was able to identify the selected control but can't SELECT it.
I am using visual studio 2015 / windows 10 Pro.
1.Make Project
New Project -> Windows Forms application
-> name : sample -> [OK]
2.Add User Control
Add -> New Item -> User Control -> Name : usrPanel.vb -> [Add]
usrPanel.BorderStyle : FixedSingle
3.Add 2 Panel controls on usrPanel
Add Panel control on usrPanel
name : pnlTitle
pnlTitle.Dock : Top
pnlTitle.BackColor : Maroon
Add one more Panel
name : pnlMain
pnlMain.Dock : Full
4.Modify usrPanel.vb like this
Imports System.ComponentModel
Imports System.Windows.Forms.Design
Imports System.Windows.Forms.Design.Behavior
<Designer(GetType(usrPanelDesigner))>
Public Class usrPanel
End Class
Public Class usrPanelDesigner
Inherits ParentControlDesigner
Private myAdorner As Adorner
Public Overrides Sub Initialize(component As IComponent)
MyBase.Initialize(component)
If (TypeOf MyBase.Control Is usrPanel) Then
MyBase.EnableDesignMode(DirectCast(MyBase.Control, usrPanel).pnlTitle, "Title")
MyBase.EnableDesignMode(DirectCast(MyBase.Control, usrPanel).pnlMain, "Main")
End If
myAdorner = New Adorner()
BehaviorService.Adorners.Add(myAdorner)
myAdorner.Glyphs.Add(New MyGlyph(BehaviorService, Control))
End Sub
End Class
5.Paste this entire sample below.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.design.behavior.behavior?redirectedfrom=MSDN&view=netcore-3.1
Class MyGlyph
Inherits Glyph
Private control As Control
Private behaviorSvc As _
System.Windows.Forms.Design.Behavior.BehaviorService
Public Sub New(ByVal behaviorSvc As _
System.Windows.Forms.Design.Behavior.BehaviorService, _
ByVal control As Control)
MyBase.New(New MyBehavior())
Me.behaviorSvc = behaviorSvc
Me.control = control
End Sub
Public Overrides ReadOnly Property Bounds() As Rectangle
Get
' Create a glyph that is 10x10 and sitting
' in the middle of the control. Glyph coordinates
' are in adorner window coordinates, so we must map
' using the behavior service.
Dim edge As Point = behaviorSvc.ControlToAdornerWindow(control)
Dim size As Size = control.Size
Dim center As New Point(edge.X + size.Width / 2, edge.Y + _
size.Height / 2)
Dim bounds1 As New Rectangle(center.X - 5, center.Y - 5, 10, 10)
Return bounds1
End Get
End Property
Public Overrides Function GetHitTest(ByVal p As Point) As Cursor
' GetHitTest is called to see if the point is
' within this glyph. This gives us a chance to decide
' what cursor to show. Returning null from here means
' the mouse pointer is not currently inside of the glyph.
' Returning a valid cursor here indicates the pointer is
' inside the glyph,and also enables our Behavior property
' as the active behavior.
If Bounds.Contains(p) Then
Return Cursors.Hand
End If
Return Nothing
End Function
Public Overrides Sub Paint(ByVal pe As PaintEventArgs)
' Draw our glyph. It is simply a blue ellipse.
pe.Graphics.FillEllipse(Brushes.Blue, Bounds)
End Sub
' By providing our own behavior we can do something interesting
' when the user clicks or manipulates our glyph.
Class MyBehavior
Inherits System.Windows.Forms.Design.Behavior.Behavior
Public Overrides Function OnMouseUp(ByVal g As Glyph, _
ByVal button As MouseButtons) As Boolean
MessageBox.Show("Hey, you clicked the mouse here")
Return True
' indicating we processed this event.
End Function 'OnMouseUp
End Class
End Class
6.After Mouse Clidk I want to select the specified panel
in Design Mode
MessageBox.Show("Hey, you clicked the mouse here")
Change
'MessageBox.Show("Hey, you clicked the mouse here")
Dim myg As MyGlyph = CType(g, MyGlyph)
Dim c As Control = myg.control
c.Select()
c.Focus()
7.Build All
8.Add usrPanel control on Form1
usrPanel was displayed
click header of usrPanel -> header SELECTED
click blue point -> nothing happens
click the right edge of the usrPanel -> The entire panel is SELECTED
How do I get the usrPanel to be SELECTED when the blue point is clicked?

WinForm Designer code is all about using designer services. In this case you need to acquire an instance of the selection service that is manifested through an object that implements the ISelectionService Interface.
You acquire a service instance through an object that implements the IServiceProvider Interface. The Control.Site Property implements the ISite Interface that in turn implements IServiceProvider.
Use the IServiceProvider.GetService(Type) Method to acquire the service and then use the ISelectionService.SetSelectedComponents Method to select the desired component(s).
Public Overrides Function OnMouseUp(g As Glyph, button As MouseButtons) As Boolean
Dim myg As MyGlyph = CType(g, MyGlyph)
Dim c As Control = myg.control
Dim selService As ISelectionService = CType(c.Site.GetService(GetType(ISelectionService)), ISelectionService)
selService?.SetSelectedComponents({c})
Return True
End Function

Related

Type "Record" is not defined in custom class vb.net

I'm following the thread below to create the multi-line combobox. I'm currently using Visual Studio 2019, and that thread is from 2013.
Any way for a combo box with 2 values per line?
Code that I copied:
Public Class MultiLineComboBox : Inherits ComboBox
Public Sub New()
' Call the base class.
MyBase.New()
' Typing a value into this combobox won't make sense, so make it impossible.
Me.DropDownStyle = ComboBoxStyle.DropDownList
' Set the height of each item to be twice its normal value
' (because we have two lines instead of one).
Me.ItemHeight *= 2
End Sub
Protected Overrides Sub OnDrawItem(e As DrawItemEventArgs)
' Call the base class.
MyBase.OnDrawItem(e)
' Fill the background.
e.DrawBackground()
' Extract the Record object corresponding to the combobox item to be drawn.
If (e.Index >= 0) Then
Dim record As Record = DirectCast(Me.Items(e.Index), Record)
' Format the item's caption string.
Dim caption As String = String.Format("ID: {0}{1}Name: {2}", record.UniqueID.ToString(), Environment.NewLine, record.Name)
' And then draw that string, left-aligned and vertically centered.
TextRenderer.DrawText(e.Graphics, caption, e.Font, e.Bounds, e.ForeColor, TextFormatFlags.Left Or TextFormatFlags.VerticalCenter)
End If
' Finally, draw the focus rectangle.
e.DrawFocusRectangle()
End Sub
End Class
I created a class named MultiLineComboBox, followed the instruction exactly, and it says "Type 'Record' is not defined." I have been searching for answers on the type "record" or DirectCast (e.g. https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/operators/directcast-operator), but none of them has helped me so far.
My reputation is currently <50 so I cannot leave a comment on the answer of that thread either. Could you all please help me with this?
(added tag visual-studio-2019 and .net-4.7.2 in case VS or .NET version is the issue)
Read the whole answer. The Record class is declared there; you need it, too, and you want to change the code to match the fields for your combobox.

How can I remove the double form title bar?

I have a mdi container form that when it opens a child inside I get this double title bar with another set of close/minimize/maximize buttons and the form icon. How can I get rid of it? I've tried setting Control to false but it does not work. FormBorderStyle to none also does not work and it deforms the child form.
Also, I have a toolstrip that contains some buttons and it has this annoying border looking line at the bottom (check out the blue arrow I drew). How can I disable that aswell?
First Part
For the first part of your question, the workaround posted here by Mr. #RezaAghaei could be the answer. Here's the VB.NET version:
Public Class YourParentForm
'Or drop one in the designer...
Private ReadOnly ContainerPanel As Panel
Sub New()
InitializeComponent()
IsMdiContainer = False
ContainerPanel = New Panel With {.Dock = DockStyle.Fill}
Controls.Add(ContainerPanel)
End Sub
End Class
And where you create the child Form:
Dim f As New ChildForm With
{
.FormBorderStyle = FormBorderStyle.None,
.TopLevel = False,
.ControlBox = False,
.Dock = DockStyle.Fill,
}
ContainerPanel.Controls.Add(f)
f.Show()
Since the last inserted control into the collection is docked first, you need to explicitly set the order of the controls to avoid any possible dock overlapping. So as you noticed and mentioned in your comment, the Dock.Fill Form is overlapping the Dock.Top Label. To fix that:
Dim f As New ChildForm With
{
.FormBorderStyle = FormBorderStyle.None,
.TopLevel = False,
.ControlBox = False,
.Dock = DockStyle.Fill
}
ContainerPanel.Controls.Add(f)
Controls.SetChildIndex(ContainerPanel, 0)
Controls.SetChildIndex(Label1, 1)
f.Show()
In fact you can omit Controls.SetChildIndex(Label1, 1), just added to clear up the idea.
If you'r using the designer to add the ContainerPanel, select it and right click, you will see in the context menu Bring to Front and Send to Back which are used to do the same thing. Also, you can use the Document Outline window (Ctrl + T to show it) to change the order of the controls using the up/down arrows and the left/right arrows to move controls to different containers.
Second Part
As for the second part, you need to create a new class that inherits the ProfessionalColorTable and override the ToolStripBorder property to prevent it from returning the default color when rendering the ToolStrip:
Public Class CustomColorTable
Inherits ProfessionalColorTable
Public Overrides ReadOnly Property ToolStripBorder As Color
Get
Return Color.Empty
End Get
End Property
End Class
Then, pass the custom color table to a new instance of the ToolStripProfessionalRenderer class and assign it to the ToolStrip.Renderer or the ToolStripManager.Renderer properties.
Revisiting the constructor of the parent Form:
Sub New()
InitializeComponent()
ContainerPanel = New Panel With {.Dock = DockStyle.Fill}
Controls.Add(ContainerPanel)
ToolStrip1.Renderer = New ToolStripProfessionalRenderer(New CustomColorTable) With {
.RoundedEdges = False
}
'Or
'ToolStripManager.Renderer = New ToolStripProfessionalRenderer(New CustomColorTable) With {
' .RoundedEdges = False
'}
End Sub

Remove Properties and Events from UserControl vb.net

I´m devoloment my own userControl with vb.net. I´m new with this task.
I want to remove default properties.
After google, I found several topics, like this:
Removing certain properties in a user control, i.e. forcing one value and not editable in Design mode
So, I´m trying to use it, but doesn´t works for me. I don´t know what I missing or doing wrong.
Public Class MyControlDesigner
Inherits System.Windows.Forms.Design.ControlDesigner
Protected Overrides Sub PreFilterProperties(ByVal properties As System.Collections.IDictionary)
MyBase.PreFilterProperties(properties)
properties.Remove("BackColor")
properties.Remove("ForeColor")
properties.Remove("Font")
End Sub
End Class
<DesignerAttribute(GetType(MyControlDesigner))> _
Public Class MyUserControl
' ...
End Class
To hide overwrite properties I follow this topic Hiding inherited properties and this works fine, for some of them.
<Browsable(False), EditorBrowsable(EditorBrowsableState.Never)> _
Public Shadows Property AutoScroll() As Boolean
Get
Return m_AutoScroll
End Get
Set(ByVal value As Boolean)
m_AutoScroll = value
End Set
End Property
But still, I have other properties that I don´t know how to hide or remove. Like Font, ForeColor, Margin etc...
Thanks advanced
Edit: Once I finish my control, I don´t want to see, all the properties like the picture, Only I want to show mine´s.
Edit: Add code from #Plutonix
I do not have access to that control/tool/property editor, but you can try to use a TypeConverter. This works with a control that inherits from UserControl to hide properties from a Property Grid, but it wont hide them from the VS IDE property editor.
The VS IDE uses reflection to get the property list and apparently ignores the TypeConverter. If your tool does something similar, this wont work - again, I dont have the tool to test it, but it is simple and worth a try.
I created an actual UserControl with a few controls on it. Then:
Imports System.ComponentModel
Public Class YControlConverter
Inherits TypeConverter
Public Overrides Function GetPropertiesSupported(context As ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function GetProperties(context As ITypeDescriptorContext,
value As Object,
attributes() As Attribute) As PropertyDescriptorCollection
Dim propNames() As String = {"backcolor", "forecolor",
"autoscroll", "autoscrollminsize",
"autoscrollmargin", "autoscrolloffset",
"autoscrollposition"}
Dim pdc As PropertyDescriptorCollection = TypeDescriptor.GetProperties(context.Instance)
' collection to store the ones we want:
Dim myPDCList As New List(Of PropertyDescriptor)
For Each pd As PropertyDescriptor In pdc
If propNames.Contains(pd.Name.ToLowerInvariant) = False Then
myPDCList.Add(pd)
End If
Next
Return New PropertyDescriptorCollection(myPDCList.ToArray())
End Function
End Class
Then decorate your usercontrol with the TypeConverter:
<TypeConverter(GetType(YControlConverter))>
Public Class YControl
This basically runs thru the PropertyDescriptorCollection for the control and filters out the unwanted properties before returning the new collection. If it works, just add the names to the propNames array that you want to hide. View in a PropertyGrid:
As you can see, all the AutoScroll... properties are removed as well as BackColor. The others are gone as well. If the editor will use your TypeConverter instead of reflection, it should work.
--
How to test your TypeConverter using a PropertyGrid. Using a form with a property grid and a button, in the button click:
Dim yp As New YControl
PropertyGrid1.SelectedObject = yp
If the AutoScroll... properties are missing from the prop grid, your TypeConverter works! If they still show in the other tool, it is using reflection like VS.

Emit Reflection (vb.net) Dynamically Reflect dropbox results in property grid

trying to add a dropdown into a property grid
Im using VS2010 VB.net with reflection
For my full solution - Download it here
https://www.nyvault.com/files/reflection/xml_propgrid_reflect_sk.zip
Password is
1
The point of this project is to populate a propertyGrid
I dont want to create a custom grid, i just want to populate the already made out of the box generic microsoft thing.
basically, I get the class to be created with reflection. using data from XML
Some of the fields use a custom type (this will be used for the dropdown)
This is what happens when I run the solution:
So i make the class, and it looks fine
It creates everything and sets it up. then when I make an instance of this class in my MAIN()
in calls a default constructor [new()] for the type(which is hardcoded dropdown items) instead of the custom constructor I wanted [new(byval test as integer)]
basically here are the class constructors for the custom type (located in customlist.vb)
Public Sub New()
' Gather all the localized strings currently loaded
' Gather all the strintTables from the current project.
For i As Integer = 0 To 4
myStringCollection.Add(New MyString(100 + i, "Test " & i))
Next
End Sub
Public Sub New(ByVal val As Integer)
For i As Integer = 0 To val
myStringCollection.Add(New MyString(100 + i, "Testy " & i))
Next
End Sub
it calls the Public Sub New()
but i want to call the Public Sub New(ByVal val As Integer)
please help, this has been making me rip my hair out for two months.

How to access to the properties of an UserControl from code side?

make my own UserControl and I can aggregate new TabPages to a TabControl and then, inside of then TabPage, I add my own UserControl using the following code.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim TabX As New Windows.Forms.TabPage("Tab " & TabCount.ToString) '(ConfiguracionTabPage)
Dim MyControl As New ClientesEmpresa
MyControl.Name = "Control" & TabCount.ToString
If ClientesTabControl.TabPages.Count = 10 Then
ClientesTabControl.TabPages.RemoveAt(9)
End If
TabX.Controls.Add(MyControl)
TabX.Name = "Tab" & TabCount.ToString
TabX.Text = "Tab" & TabCount.ToString
MyControl.TitularLbl.Text = "Coca Cola"
Me.ClientesTabControl.TabPages.Insert(0, TabX)
Me.ClientesTabControl.SelectedIndex = 0
TabCount += 1
End Sub
My user control have several Labels, TextBox and TabPages(inside of a TabControl).
Now I want to change some properties dynamically from the source code, but I don't know how to access them.
The most similar theme that I found is this How to Acces of an User control in c#, but, as the title says, is in C#, how I can do it in VB.NET?
Sorry, I just notice that the Enter key post the comment. :(
Thanks for your feedback, I understand what are you saying but I missing something in the middle.
When I create the control in running time in the above code I can access easily to the properties of the created object, in this case my UserControl, but I don't understand how to reach the properties of a particular instance of that control from outside of Button_Click; ie. another button_click event(second button)
I was thinking to use something like
Dim ControlList As Windows.Forms.Control() = Me.ClientesTabControl.TabPages(0).Controls.Find("ModeloLbl", True)
or
ClientesTabControl.TabPages(0).Controls.OfType(Of AlarmasVehiculo)()
But I'm stuck here.
------------------------------------- 3th post ---------------
Thanks Steve, I was resolved using "Control.Find" and a For Each but your solution is easier.
There's any way to get the name of the selected tab or I must to create an Array when I create the New TabPage?, the idea is to update the text of the controls inside of the selected tab only when is selected by the user or every 5 seconds but just the in selected one.
Thanks.
To borrow M4N's answer from the C# question, and translate it to VB:
Cleanest way is to expose the desired properties as properties of your usercontrol, e.g:
Public Class MyUserControl
' expose the Text of the richtext control (read-only)
Public ReadOnly Property TextOfRichTextBox As String
Get
Return richTextBox.Text
End Get
End Property
' expose the Checked Property of a checkbox (read/write)
Public Property CheckBoxProperty As Boolean
Get
Return checkBox.Checked
End Get
Set (value As Boolean)
checkBox.Checked = value
End Set
End Property
'...
End Class
In this way you can control which properties you want to expose and whether they should be read/write or read-only. (of course you should use better names for the properties, depending on their meaning).
Another advantage of this approach is that it hides the internal implementation of your user control. Should you ever want to exchange your richtext control with a different one, you won't break the callers/users of your control.
To answer your second question, if you need to access your dynamically created controls, you can do so easily using their names, for instance:
Dim c As ClientesEmpresa= CType(Me.ClientesTabControl.TabPages("Tab1").Controls("Control1"), ClientesEmpresa)
c.CheckBoxProperty = True