VB.NET Adding list of property in Designer to choose from - vb.net

First excuse my my english, I'm french.
I have made a control (a class in fact) inherited from textbox.
The purpose of this class is simply to keep the textbox aligned above a column of a datagridview.
All is working correctly. But I have a question :
I made a datagridview property, and in design time, I can simply select it in a combobox listing the datagridview of my form.
But I have also a columnName property as a string. I would like that, once the datagridview is selected, the designer propose me the list of the datagridviewcolumn name in this property.
I have absolutly no idea how to achieve that. I'm a very beginner in code, and have made no studies on it.
I tried making the string property into a datagridviewcolumn property, but not only did the designer do not propose me the ones available, but also it crashes and I have to remove all about this textbox in the file.Designer.vb.
Thank you for your help.
EDIT : Here is the code :
Public Class TextBoxFilter
Inherits TextBox
Private WithEvents _DGV As DataGridView = Nothing
Public Property DGV As DataGridView
Get
Return _DGV
End Get
Set(value As DataGridView)
_DGV = value
End Set
End Property
Private _ColumnName As String = String.Empty
Public Property ColumnName As String
Get
Return _ColumnName
End Get
Set(value As String)
_ColumnName = value
End Set
End Property
The rest of the code is irrelevant. Just know that it features event (when datagridviewcolumns are move, not displayed, not visible) to adjust the textbox.
To answer Plutonix, I would like to be able to give the designer a list of column, even if there is several datagridview in the form, and even if it can't find them automatically. I suppose I could do that in the set of the datagridview ? But I don't know how.

Related

ToString not updating on object when altering ListBox in VB

I have a form that alters the content of a class within a list box. The information is updated correctly, but my ToString override on my object doesn't refresh - meaning the old ToString doesn't change. How would I fix this?
Here's my object:
Public Class Destination
Public strDestinationName As String
Public strAddress As String
Public intQuality As Integer
Public intPrice As Integer
Public Overrides Function ToString() As String
Return strDestinationName
End Function
End Class
Here's the code where it should be updated
Dim selectedDestination As Destination
selectedDestination = CType(ListForm.lbNames.SelectedItem, Destination)
selectedDestination.strDestinationName = tbName.Text
selectedDestination.strAddress = tbAddress.Text
selectedDestination.intPrice = cbPrice.SelectedIndex
selectedDestination.intQuality = cbQuality.SelectedIndex
Me.Close()
Regardless of how you add items to a ListBox, it is the ListBox that actually displays the data. In your case, it appears that you are adding Destination objects to the ListBox somehow, given that the SelectedItem is a Destination object. Given that you have written that ToString method, you are presumably relying on that to produce the text that the ListBox displays for each item. You are now expecting to be able to change the value of the strDestinationName field of one of the items and have the ListBox reflect that change. How exactly do you think that is going to happen?
The ToString method has to be called in order to get the new value and who do you think is going to call it? It would be the ListBox that calls it because it is the ListBox that displays the result. When you change that field, you are expecting the ListBox to call your ToString method but why would it do that? What reason has the ListBox got to call that method? It has no knowledge of the change you made so why would it think that it has to get new data?
The solution to your problem is to change your code in some way to notify the ListBox that data has changed so that it knows that it needs to get that new data and display it. There are multiple ways that you could do that.
The simplest option would be to bind your data to the ListBox via a BindingSource and then, when you modify an item, call the ResetItem method or similar of the BindingSource. That will raise an event that is handled by the ListBox and the ListBox then knows that it needs to refresh the data for that item. That is what will prompt the ListBox to call your ToString method and get the new data to display. You would add the BindingSource to the form in the designer and then do the binding where you are currently adding the items, e.g.
Dim destinations As New List(Of Destination)
For i = 1 To 10
Dim d As New Destination
d.strDestinationName = "Destination " & i
destinations.Add(d)
Next
destinationBindingSource.DataSource = destinations
destinationListBox.DataSource = destinationBindingSource
The modification would look something like this:
Dim selectedDestination = DirectCast(destinationBindingSource.Current, Destination)
selectedDestination.strDestinationName = "New Destination"
destinationBindingSource.ResetCurrentItem()
The Current property returns the item currently selected in the bound UI and the ResetCurrentItem method notifies the bound UI to refresh the display of that item.
This is really not the best way to go about it though, given that you have control over the item type. What you ought to do is implement the type using properties rather than fields, get rid of the ToString method that only returns the value of one property and then add a change event to that property:
Public Class Destination
Private _destinationName As String
Public Property DestinationName As String
Get
Return _destinationName
End Get
Set(value As String)
If _destinationName <> value Then
_destinationName = value
OnDestinationNameChanged(EventArgs.Empty)
End If
End Set
End Property
Public Property Address As String
Public Property Quality As Integer
Public Property Price As Integer
Public Event DestinationNameChanged As EventHandler
Protected Overridable Sub OnDestinationNameChanged(e As EventArgs)
RaiseEvent DestinationNameChanged(Me, e)
End Sub
End Class
You can now bind a list of Destination objects directly and specify any of those properties as the DisplayMember to have that property value displayed:
Dim destinations As New List(Of Destination)
For i = 1 To 10
Dim d As New Destination
d.strDestinationName = "Destination " & i
destinations.Add(d)
Next
destinationListBox.DisplayMember = "DestinationName"
destinationListBox.DataSource = destinations
You don't need the ToString method because the DisplayMember specifies that the value of the property with that name should be displayed. When you modify the value of the DestinationName property of an item, it will raise the DestinationNameChanged event and that will notify the ListBox that it needs to refresh the display for that item, so you don't need any additional code to make the ListBox update.
That's fine if you only plan to modify existing items. There's still a problem if you want to add and/or remove items after binding though. The List(Of T) class that is used to bind the items to the control in this example does not have any events to notify the control of changes to the list like that. In that case, you can use a BindingSource again if you want. If you add and remove items via the BindingSource then it will raise that appropriate events and the ListBox will update. If you wanted to add and remove via the underlying list then you'd have to call an appropriate method of the BindingSource when you made a change.
An alternative would be to use a BindingList(Of Destination) instead of a List(Of Destination). As the name suggests, the BindingList(Of T) class is made for binding, so it will automatically raise the appropriate events when the list changes to enable the UI to update without extra code from you. Using the combination of property change events in your item class and a BindingList(Of T), you can add, edit and remove items in the bound list and the UI will reflect those changes automatically.

Visual Basic Datagridview cell event then press keyboard enter

I have a problem and I don't understand how to solve it, if this is possible. I have a datagridview and I want to have a event then into one cell text I entry new line (keyboard enter), I now there are a event "grid_keydown" or "grid_keypress", but this two work only then I select the datagridview full row and not for each datagridview cell. There are a solution to config datagridview properties to work this 2 event also for each datagridview cell editing? Thank you a lot
So I finally found a solution to achieve what you are looking for. The bad news: It´s more tricky than I thought (and should be imho). Anyway you need the following steps:
Create a custom DataGridViewTextBoxEditingControl class.
It is to override the default behavior that the Enter key accepts the changes in the Cell and switches to the next row. It also attaches a NewLine to the current cell text.
Public Class MyDatagridTextBoxEditControl
Inherits DataGridViewTextBoxEditingControl
Public Overrides Function EditingControlWantsInputKey(keyData As Keys, dataGridViewWantsInputKey As Boolean) As Boolean
If dataGridViewWantsInputKey AndAlso keyData = Keys.Enter Then
AppendText(Environment.NewLine)
Return MyBase.EditingControlWantsInputKey(keyData, False)
End If
Return MyBase.EditingControlWantsInputKey(keyData, dataGridViewWantsInputKey)
End Function
End Class
Create a custom DataGridViewTextBoxCell class.
It is to set and use the previously created DataGridViewTextBoxEditingControl type.
Public Class MyDatagridTextBoxCell
Inherits DataGridViewTextBoxCell
Public Overrides ReadOnly Property EditType As Type
Get
Return GetType(MyDatagridTextBoxEditControl)
End Get
End Property
End Class
Bind the data together inr the DataGridView.
For my example I put the code into the Form´s constructor (after
InitializeComponent()), but you can also put it into the Load
event
'Assume [Beschreibung] is column no. 5
DataGridView1.Columns.Item(4).CellTemplate = New MyDatagridTextBoxCell()
(Depending on where you put this code you might need to call DataGridVie1.Refresh()).
Remarks: This code will lead to that you are not able to accept the changed value in the text cell with the Enter key anymore. It will however accept the input when you left mouseclick outside the cell. A Esc keypress will still revert the text changes.
You might add code into EditingControlWantsInputKey which treats another key like Enter, e.g. Insert or similar.
Without this code you can achieve the same behavior with the key combination Shift + Enter

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.

Changing a Controls Property

There is something not going out of my head because i spent now several days to get an understandable answer with reading books and searching the web.
In my VS 2012 VB.net project I have a usercontrol that contains a toolstrip. The toolstrip has a toolstripdropdownbutton with a toolstripmenuitem in it. I drag this usercontrol onto a windows form. My aim is to change the text of the menuitem when I'am in the forms designer mode.
I tried to create some properties in the usercontrol for example
public property TS as Toolstrip
get
return Toosltrip1
end get
set (value as Toolstrip)
Toolstrip1 = value
end set
Doing so I can open the toolbar item collection in the property grid of the usercontrol on the windows form using the new usercontrols property TS and I am able to change the menuitems text
but when I run the windows form the old text of the menuitem is displayed and my property change is ignored.
What should I do so that the property change is not ignored.
Please help me to clear my head with this problem .
Since you are only changing the text, use this property instead :
Public Property MenuText As String
Get
Return ToolStripMenuItem1.Text
End Get
Set(value As String)
ToolStripMenuItem1.Text = value
End Set
End Property

Overriding a Custom Control's Text Property to use a Textbox's Text causes the Textbox to display the Control's name by default

Using VB.net (2005), I'm creating a custom control (a folder picker) that contains a textbox and button. Recently I've added the following:
<Browsable(True), DefaultValue(""), DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
Public Overrides Property Text() As String
Get
Return Me.uiPath.Text
End Get
Set(ByVal value As String)
Me.uiPath.Text = value
End Set
End Property
The problem I'm having is that now when the control is created, the textbox always defaults to showing the name of the control (instead of being blank). It seems the Text property is being changed after Sub New is called, however, I've checked the designer, and I cannot see where it is doing this.
I know that changing the name of the property would resolve the issue, but I would like to know why this is happening (I'm guessing it has something to do with the standard designer?), and if there is a way to resolve (or work around) it, while still using the Text property?
I don't know if it makes any difference, but I am using a custom designer:
Public Class FolderPickerDesigner
Inherits Windows.Forms.Design.ControlDesigner
Public Overrides ReadOnly Property SnapLines() As IList
Get
Dim SnapLinesList As ArrayList = TryCast(MyBase.SnapLines, ArrayList)
If (Me.Control IsNot Nothing) AndAlso (Me.Control IsNot Nothing) Then
Dim FP As FolderPicker = CType(Me.Control, FolderPicker)
SnapLinesList.Add(New SnapLine(SnapLineType.Baseline, FP.uiPath.Bottom - 5, SnapLinePriority.Medium))
End If
Return SnapLinesList
End Get
End Property
End Class
Any help / ideas would be appreciated. If this doesn't / can't be resolved, I'll mark the most helpful post as the answer...
Set(ByVal value As String)
If Me.DesignMode And (Environment.StackTrace.Contains("System.Windows.Forms.Design.ControlDesigner.InitializeNewComponent")) Then Return
BaseT.Text = value
End Set