Creating a custom control...Cannot create a 'text' property? - vb.net

Solution
I did some googling and found this forum post, and here is what I needed to do:
Imports System.ComponentModel
<EditorBrowsable(EditorBrowsableState.Always), Browsable(True), Bindable(True), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
Overrides Property Text() As String
Get
Return ControlText.Text
End Get
Set(ByVal value As String)
ControlText.Text = value
End Set
End Property
I should state that I am really new to creating custom controls, so I do not know all of the ins-and-outs of the whole process.
I am creating a custom control that functions similarly to a checkbox, but uses two images as checked/unchecked. I am trying to add a Text property, but it gives me this warning:
Property Text() As String
Get
Return ControlText.Text
End Get
Set(ByVal value As String)
ControlText.Text = value
End Set
End Property
"property 'Text' shadows an overridable method in the base class 'UserControl'. To override the base method, this method must be declared 'Overrides'."
Ok, so that is no problem. I change my declaration to Overrides Property Text() As String, but when I go to test it out 'text' is not listed under properties. Is there additional steps I need take to get my result?
More details
My control consists of 2 (or 3, depending on how you look at it):
PictureBox - Displays a checked/unchecked image
Label - The Text that is being displayed on the control
PictureCheckBox - This is the actual control's name
The PictureBox is docked to the left of the PictureCheckBox, and the Label is docked on the right side:

EDIT Scratched the bit about Text being non-virtual. It is in fact virtual / overridable.
But I'm curious, why do you want to do this. In your specific example you're just calling into the base property so it doesn't appear to do anything.
Where are you expecting this value to be shown and how are you setting it?
Text is a non-virtual / overridable method on Control. There is no way for you to override the property. If you want to re-define the property you can use the Shadows keyword.

You should make sure it's a public property

Public Overridable Property Text() As String
Get
Return ControlText.Text
End Get
Set(ByVal value As String)
ControlText.Text = value
End Set End Property

This might be a stupid question, but some of them still needs to be asked just to make sure:
Have you compiled since you made the changes? Using hotkeys in Visual Studio, press [Ctrl]+[Shift]+[b] to compile the entire solution.

Related

How do I hide "Control.Image Property" from Property Window in Visual VB or visual C++

I made a class derived from Button Class. It has two new properties: ImageNormal and ImageOver. I really want to hide the default Image property in Debug time.
Excuse me for my English, I know, I should improve it.
I solved it:
<System.ComponentModel.Browsable(False)>
Public Shadows Property Image As Image
Get
Return MyBase.Image
End Get
Set(value As Image)
MyBase.Image = value
End Set
End Property

How do I add a design-time description to a property implemented through an extender provider?

I know that I can add a design-time Designer description to a custom control's property by doing this:
<Category("Data"), Description("This describes this awesome property")>
Public Property Foo As Boolean
...
End Property
What I want to do is the exact same thing, but to properties that my extender provider component is providing other controls on my form with, so that when I click on the property's value field, for example, I would see the description I wrote for it. Searched a lot for an answer but had no success so far. Would I have to add something to my getter and setter methods for the property?
Thank you.
Would I have to add something to my getter and setter methods for the property?
Yes. Add the DescriptionAttribute to the Get[PropertyName] method. The same goes for any other Attributes (they dont seem to work on the Set... counterpart).
<Category("ListContolExtender"), DisplayName("DisplayMode"),
Description("My very clever description")>
Public Function GetDisplayMode(ctl As Control) As ItemDisplays
If extData.ContainsKey(ctl) Then
Return extData(ctl).DispMode
Else
Return ItemDisplays.Enabled
End If
End Function
Public Sub SetDisplayMode(ctl As Control, v As ItemDisplays)
If extData.ContainsKey(ctl) Then
extData(ctl).DispMode = v
Else
Dim e As New ExtenderData
e.DispMode = v
extData.Add(ctl, e)
End If
End Sub
The DisplayNameattribute hides all the DisplayMode on ListBoxExtender verbiage

vb.net modifying values of custom attributes in a class

I had an idea to use custom attributes on the properties in a class for databinding purposes in a winforms interface. For example, setting and changing the backcolor, forecolor, and tooltip on a textbox with invalid data. I find that I can bind up the control properties of txtTest for backcolor, etc., to a custom attribute such as BackColorAttr decorating a property in the class such as Name, with no problem. The property value itself is bound to the Text of the textbox, two-way binding of that works just fine, and the initial backcolor, forecolor, etc., are set from the initial values of the custom attributes just the way I had hoped. I'm doing all this through a BindingHelper class that reduces all the coding to a couple of generic methods.
Where I'm stumped is manipulating the values of the custom attributes at a later time. Changing the backcolor to red, for example. Nothing I've tried seems to work. Has anybody tried something like this, or have some guidance as to how I might proceed?
I dont quite follow the first part or what binding has to do with colors or Attributes, but thats not how Attributes work. They are not Property wrappers and Properties, Methods and Types have no idea of the Attributes associated with them (and vice-versa). They are meta data compiled into the assembly. As such, you cant change the value in any meaningful way.
Test class and test Attribute:
Public Class BarState
Inherits Attribute
Public Property State As String
Public Sub New(t As String)
State = t
End Sub
End Class
Public Class Foo
<BarState("red")>
Public Property Name As String
End Class
Since State is a property, test if we can set it:
Dim f As New Foo
' get props for the Type
Dim pi As PropertyInfo = f.GetType.GetProperty("Name")
Dim attr = pi.GetCustomAttributes(GetType(BarState), False)
If attr.Length > 0 Then
' get prop info for the State property on the Attr Type
Dim pa As PropertyInfo = attr(0).GetType.GetProperty("State")
' change it
CType(attr(0), BarState).State = "GREEN"
' or
'pa.SetValue(attr(0), "GREEN", Nothing)
' print it (prints "GREEN" but it does not persist)
Console.WriteLine(CType(attr(0), BarState).State)
End If
'get the attr again as you might do next time thru
attr = pi.GetCustomAttributes(GetType(BarState), False)
' print the value (Print "red")
Console.WriteLine(CType(attr(0), BarState).State)
The first print will be "GREEN" but that is only for this instance - it does not persist. The next time you get it, it reverts to "red". Since an Attribute is a Type, we can try to Reflection to change the value using pa.SetValue(attr(0), "GREEN", Nothing) which is commented out. It still wont persist because "red" is compiled into the assembly which is what your starting point will always be.
It might seem like you could keep a Dictionary or collection of the attribute instances for all the properties on all the types. That could work except, they all look alike, so you would have to create a hash to track which Attribute instance goes with what Property on what Type.
And you'd have to keep that collection in sync with the underlying instance objects. The Attribute instance wont know the instance it came from is gone and so the state setting should revert, so your Attribute manager would need to handle that.
You might look into "weavers" which use attributes to tag things (like a value range) then rewrite the assembly to weave in range checks for the tagged properties. Sort of sounds like what you are after I dont know what else they might do along the lines of what you describe.

How to add a "sub property" to a class property

If, in code, I wanted to do something like the following, what would my class definition need to look like? (Keep in mind the fruit/language thing is just an example)
dim myfruit as new fruit()
myfruit.name = "apple"
myfruit.name.spanish = "manzana"
Here is the class I have, just not sure how to add the "sub property".
Public Class Fruit
Private _name As String
Public Property name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
End Class
In general, for you to have a "sub property", you'd need to make your Property a class itself. This would mean the subproperty is actually a property on the class exposed by the top level property.
Effectively, you'd change the name property from a string to a "Translations" class or similar, ie:
Public Class Fruit
Public Property Name As New Translations
End Class
Public Class Translations
Public Property Primary As String
public Property Spanish As String
End Class
However, this will likely break the code you're displaying, as the second line would need to have a different syntax, ie:
myfruit.Name.Primary = "green"
myfruit.Name.Spanish = "verde"
However, if the goal here is to just handle translation of your user interface, there are other options. For details, see Introduction to International Applications Based on the .NET Framework on MSDN.
I initially thought Reed´s answer was what I was after. In my application, I wanted to use the "sub-property" to set a property on a Form Label. (I was trying to emit only the Label properties I wanted available to a Custom Control.)
I tried this:
Public Class Fruit
Private _name As New Translations
Public Property Name As Translations
Get
Return _name
End Get
Set(value As Translations)
_name = value
_PrimaryCaps = _name.Primary.ToUpper
End Set
End Property
'Private variable is automatically added for unexpanded property
Public Property PrimaryCaps As String
End Class
Public Class Translations
Public Property Primary As String
Public Property Spanish As String
End Class
Then
Dim myFruit As New Fruit
myFruit.Name.Primary = "Apple"
myFruit.Name.Spanish = "Manzana"
Dim primaryCaps As String = myFruit.PrimaryCaps
Weirdly - to me at least - this doesn't work; myFruit.PrimaryCaps returns nothing rather than the hoped-for "APPLE". It appears that the Set for Name is never executed. (Placing the _PrimaryCaps assignment above the Get Return does work, however.)
(I realize that a PrimaryCaps property could be added to the Translations class but, again, this doesn't help if you're wanting to set a foreign variable from within an instance of Fruit.)
I don't know if this is "by-design", whether I've simply misunderstood the intended functionality or what. One thing I did alight on after further research was that this structure isn't very common at all in .NET; for example setting a control's size is done as follows:
oControl.Size = New Drawing.Size(20, 15)
rather than simply setting, say, the Width property directly:
oControl.Size.Width = 20
(The latter won't compile: "Expression is a value and therefore cannot be the target of an assignment.")
If anyone has any more insight than I on this, I'd love to hear it. I know this could simply be done by using an instance of Fruit, for example, but that's not the point.

Intellisense for member override in VB.Net 2008 Express Edition

If I override a member (e.g AutoSize in the Button Class), then the intellisense no longer appears in the editor, forcing me to re-decorate the property.
Is there an option somewhere that I need to check?
ETA: Here's a code sample:
Public Class MyButton
Inherits Button
Public Overrides Property AutoSize() As Boolean
Get
Return MyBase.AutoSize
End Get
Set(ByVal value As Boolean)
MyBase.AutoSize = value
End Set
End Property
End Class
If I then type:
Dim b as New MyButton
b.AutoSize ...
The intellisense explaining the AutoSize property doesn't appear.
Whether a property is visible in IntelliSense is controlled by the [EditorBrowsable] attribute. VB.NET is a bit special because it hides EditorBrowsableState.Advanced by default.
None of this would apply to an override to Button.AutoSize, it is always visible. Maybe you can give a better example, a code snippet is always good.