Passing a method as a parameter .net - vb.net

I have been searching for quite a while today for an answer to my question but without success. I don't even know if its possible but I'll try my luck here.
Lets say i have this function somewhere in a class:
Public Sub sub1(i as Integer, uc as UserControl)
...
End Sub
And somewhwere else, in an other method i have this call:
sub1(46, new UserControl())
The problem is that i want to pass a UserControl with, lets say, a background colored in blue but it must be defined inside the method call. In other words, i want to pass an object with some properties that are modifed outside the constructor and everything must be done inside the method call. I'm thinking of something like that:
sub1(9387, {Dim uc as new UserControl()
uc.BackColor = Color.Blue
return uc} )
I understand that i could define a UserControl and modify it before the method call but my real situation is way more complex than that. Anyway I just want to know if it is currently possible and if yes show me some examples. In my research i found that i could do some delegate or use some "lambda" expression but I didn't find a solution that perfectly solve my question. And again, I must not write a single character of code outside the method call.
Thanks in advance!

Like this:
sub1(9387, New UserControl With {.BackColor = Color.Blue})

Immediately-invoked functions are possible in VB.NET:
Dim result As Integer = (Function() As Integer
Return 1
End Function)()
Or in your example:
sub1(9387, (Function()
Dim uc As New UserControl()
uc.BackColor = Color.Blue
Return uc
End Function)())

If I'm understanding your question, you can simply use property initializers:
sub1(9387, New UserControl With { .BackColor = Color.Blue })

Related

ExpandoObject PropertyChanged event not triggering in propertygrid

Basically I am loading a JSON object that contains combinations of values available or not at run time, so I need to know when a specific property is modified to then toggle all the other browsable etc.. and though that the PropertyChange event was the perfect way to handle it.
So I can add an event handler to get triggered on my expandoobject like this:
Dim test As Object = new ExpandoObject
AddHandler CType(test, INotifyPropertyChanged).PropertyChanged, AddressOf expando_PropertyChanged
and the handler is as basic as it gets
Public Shared Sub expando_PropertyChanged(ByVal sender As Object, ByVal e As PropertyChangedEventArgs)
Debug.Print("Property {0} set or changed", e.PropertyName)
End Sub
so far this works, if I add or modify a property right after that, I get notified.
however if I return this and set it as the selectedobject of my propertygrid, I cannot get the event to trigger.
I'm using a custom PropertyDescriptor and ICustomTypeDescriptor to set a few other attributes for the propertygrid, so I assumed it might be as easy as setting the attribute
<RefreshProperties(RefreshProperties.All)>
but I cannot find a way to override the Refresh in the PropertyDescriptor unlike Browsable or readonly, which kinda makes sense as the property grid would need to know ahead of time that it needs to be refreshable.
So I could not make the INotifyPropertyChanged work with the expando, it would work with a dynamicObject where I would implement it myself but that was requiring too much of a rewrite for me.
I ended up add a lambda on my expando that I call on the PropertyDescriptor SetValue
CType(_expando, Object).toggleSwitches.Invoke(_expando, _name, value)
note the use of Invoke here in vb.net that was also a PITA but I found this guy who had the same issue as I did: https://github.com/dotnet/vblang/issues/226
It is not necessary to use invoke in C# and as 99% of the examples are in C# it took me more time than I wanted to implement it.
Hopefully this will help someone too.
here is the lambda if interested as well:
_expando.toggleSwitches = Sub(obj As Object, caller As String, value As Object)
Debug.Print(caller & " " & value.ToString())
End Sub

How do I write a VB class which allows indexing into/calling an instance?

I'm honestly not sure what this is called, and if I did I'm sure I could google it in about 5 seconds.
I want to be able to write a class that I can sort of "index into" the way you do with a collection, eg:
Public Class FooClass
Public Function magicKeyword(param as String) as String
If param = "foo" Then
Return "bar"
Else
Return "baz"
End If
End Function
...
End Class
And then use it like this:
Dim myObj as New FooClass
Dim output as String = myObj("foo") '<-- this is what I want to know how to do
' output = "bar"
What is this called, and what syntax would I use for the function?
Out of curiosity, can this also be done as a Shared function so the class itself can do it? e.g.:
Dim output as String = FooClass("foo")
What you are describing is implementing a custom collection, and Microsoft provides a pretty good guide on how to accomplish this.
It should be said, however, that the collection classes already provided in .NET should be able to handle most use cases. A truly custom collection is overkill in many instances.

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

Syntax – can be a class method called at New without a helper variable?

Having sample trivial class
Class A
Property Property1 As Integer = 5
Sub Action1()
Debug.Print(Property1.ToString())
End Sub
End Class
I can always call Action1() like
Dim instanceA As New A
instanceA.Action1()
But can I call the method without using the variable? Something like
(New A).Action1()
I'm getting syntax error at the 1st character when attempting that.
The reason that you get a syntax error is that a line of VB code cannot begin with the New keyword. I find that the best way around that is to use the otherwise useless Call keyword:
Call New A().Action1()

Using CallByName to set Item(x) property

As a bit of background, I have a .net <-> COM object bridge that uses VB.net as a middleman, with a lot of reflection to get the job done.
I've run into a hurdle where I'm needing to use CallByName() to set a pretty standard property which is defined as
Public Default Property Item (
index As Integer
) As String
Get
Set
which would normally be called as .Object(1) = "new value", however the bridge code at the moment tries to get .Object(1) as an object then call Set on it using CallByName() (which obviously doesn't work).
With other collections I am happily able to use CallByName() to make method calls .Clear() and .Add("new value") but this property doesn't have these methods and besides, I'd like to solve it for a more generic approach so that code from the other side of the bridge can call the .Object directly.
Is someone able to suggest a way to Set an array-type property directly using CallByName(), or perhaps suggest an alternative reflection function that can be called to achieve this?
The default property can be used as a normal property, using its name. So, given a class:
Class Foo
Default Public Property Item(index As Integer) As String
Get
'...
End Get
Set(value As String)
'...
End Set
End Property
End Class
These three property assignments all have the same effect:
Dim Bar As New Foo
Bar(1) = "x"
Bar.Item(1) = "x"
CallByName(Bar, "Item", CallType.Set, 1, "x")
For array-type properties, the parameter(s) are passed to CallByName before the value when setting.
You did not show how you were using CallByName on that property, which leaves us to guess what is wrong. The syntax of .Object(1) = "new value" is also a little confusing: does the leading dot means that Object itself is some sort of collection on some other Type?
The basic answer lies in looking at the declaration, not how it is used normally. The fact that you can omit "Item" normally because it is the Default, does not apply here:
'foo(1) ==> foo.Item(1) = "Ziggy" ==>
CallByName(foo, "Item", CallType.Set, 1, "Ziggy")
The procName argument would be the property name, Item in this case. CallType.Set means you want the prop setter (Let or Set seem to both work). The first argument would be the index of the item to set/get, the last would be the data to pass.
If .Object is supposed to mean you are trying to reference a collection property, then the answer is about the same:
'foo.bars(1) ==> foo.Bars.Item(1) = "Zoey" ==>
CallByName(foo.Bars, "Item", CallType.Set, 1, "Zoey")