vb.net get local resource name from control property - vb.net

How can i get the name of a local resource that has been assigned to a control property like BackgroundImage?
For example, i have a button and i have set the BackgroundImage property to a local resource image.
What i want, is at runtime to get the name of the local resource that has been assigned to BackgroundImage of that button.

If you look at your image:
you can see two things about the way your resources are handled. First, the return is a Bitmap, so once assigned to a button or whatever, you would have a very hard time determining what it is from the image data. The second thing is that the identifiers are actually Properties not just tokens or keys into a collection. The IDE generates these in your Resources.Designer.vb file to provide access to the various resources. Here is the interface to get the bitmap of the French Flag from the resource designer file:
Friend ReadOnly Property FRFlag() As System.Drawing.Bitmap
Get
Dim obj As Object = ResourceManager.GetObject("FRFlag", resourceCulture)
Return CType(obj,System.Drawing.Bitmap)
End Get
End Property
Yours will have things like Property error_button24BUTTON_DISABLED. Like any other property, the name of the property is not part of the return, just the data associated with them.
Since what really matters is the state of the button, not the image being shown, and that Enabled state is very easy to evaluate, not much is lost just using an if statement:
If thisButton.Enabled Then
thisButton.BackGroundImage = My.Resources...
Else
thisButton.BackGroundImage = My.Resources...
End If
You would have had to do something like this to convert "True" for Enabled to "BUTTON_ENABLED" to create the resource "key" if it actually worked the way you thought it did, or was intent on getting it via Reflection.
There are several alternatives. One might be to write an ExtenderProvider to provide various state images for the controls you are working with, subclass them or just use a local Dictionary/HashTable like an Extender would:
Friend Class ButtonImages
' ToDo: load these from My.Resources in the ctor for a given button
' ...
Private Property EnabledImage
Private Property DisabledImage
Public Function GetStateImage(b As Boolean) As Bitmap
If b Then
Return EnabledImage
Else
Return DisabledImage
End If
End Function
End Class
Private myBtnImgs As New Dictionary(of Button, ButtonImages)
thisButton.BackgroundImage = myBtnImgs(thisButton).GetStateImage(thisButton.Enabled)
It is more involved than a simple If statement, but comes close to what you seem to have been looking for.

Related

How to Build a List of Form Controls Before the Form is Loaded

I’m new to OOP and VB.NET, so please bear with me.
In VB.Net I currently have working code that defines, for each form, significant information about selected controls on the form.
I have defined in a public class:
Public Class FormFld
Public Property ScrField As Control ' A control on the form
Public Property DbField As String ' Its corresponding field name in the database
… ' Other info about the control or its database field
End Class
When each form loads, I create a list of FormFlds for the form’s selected controls:
At the start of each form
ReadOnly FormFlds As New List(Of FormFld)()
and in the form’s Load routine
FormFlds.Add(New FormFld With {.ScrField = Control1Name, .DbField = "Field1Name", …})
FormFlds.Add(New FormFld With {.ScrField = Control2Name, .DbField = "Field2Name", …})
…
This technique has worked well to easily loop through the selected fields and, on input, populate those fields from the database, or, on output, write those field values to the database.
With this implementation, however, the list must be built every single time the form is loaded. I’m wondering if the setup of the list can be done only once, during program initialization, before the forms are loaded.
Here’s the latest that I have tried.
In Class1:
Public Class indiv
Public FormFlds As List(Of FormFld)() ' The list for the frmIndividual form
End Class
In Module1, I attempt defining the FormFlds for the eventual form frmIndividual, to be saved as Indiv.FormFlds. I’d like the form name (f) and the list owner (owner) to be defineable so I can easily change those for each form.
Dim owner As New indiv
Dim f As FrmIndividual
owner.FormFlds.Add(New FormFld With {.ScrField = f.TxtKey, .DbField = "Sort_Key", …})
In Visual Studio, the third line shows error “BC30456: 'Add' is not a member of 'List(Of FormFld)()”.
Wondering if the problem might be due to not having an actual form FrmIndividual created yet, I tried changing the second line to
Dim f As New FrmIndividual
but it didn’t change anything.
I’m using VS 2022, v17.2.1. If there’s more info you need, please let me know.
The reason that you're told there's no Add method is because arrays have no Add method and you have an array. Here:
ReadOnly FormFlds As New List(Of FormFld)()
You are using the New keyword to invoke a constructor, so the parentheses at the end are for the argument list for that method call. Here:
Public FormFlds As List(Of FormFld)()
there's no New keyword so there's no constructor, so the parentheses at the end indicate that the field is an array type. That code is functionally equivalent to this:
Public FormFlds() As List(Of FormFld)
When you get that field you're getting a reference to an array of List(Of FormFld), not just a single List(Of FormFld) object. Of course, the field is initially Nothing anyway, so you'd have to assign something to it first to be able to use it.
By the way, the error message was already telling you what the issue was:
'Add' is not a member of 'List(Of FormFld)()`
It is telling you that Add is not a member of array of List(Of FormFld), which it's obviously not.

Accessing an element of a custom type list by property value

Let's say I have a class called ControlInfo, which has the following properties:
Public Property Control As Control
Public Property ControlState As Int32
Now I want to create a method for accessing a specific instance of ControlInfo from a List, so I do this:
Public Function GetInstance(control As Control) As ControlInfo
For Each c As ControlInfo In list
If c.Control.Name = control.Name Then
Return c
End If
Next
Return Nothing
End Function
Is there a better way to access specific instance from a list of a custom class based on its property value? Is the loop approach bad for performance?
Sidenote: I have also considered the implementation of a Dictionary other than a List (so I would access an instance via a key, which can be a lot better than looping through all the values), but I feel that if I resort to that I would be avoiding a problem instead of solving it. Maybe I am being paranoid but I would like to know other valid approaches here, and be more certain of what should/shouldn't be done.
Thanks.

Advantages of Properties in Classes

I've been using classes for a while now, but I feel I may have been using them incorrectly.
When I create the properties for the class, I just use public variables so I end up with something like the following:
Class clsMyClass
Public Name As String
End Class
However, I've been reading some info on the net and they suggest that it should be set up in the following way:
Class clsMyClass
Private Name As String
Property UsersName() As String
Get
Return Name
End Get
Set(ByVal Value As String)
Name = Value
End Set
End Property
End Class
Is the way I'm doing it extremely incorrect? If so, why? I feel like the second method adds some sort of security but to be honest, it just looks like unnecessary code..?
One advantage of properties is that they let you customise the access to your private fields and enable you to do more so you can do the following (examples, it's not limited to that):
Make a property read-only for public access
Raise an even when a property is updated
Update other private fields when a property is updated
Validate the value that is being set
See below advantages of Properties over Variables from the C# in Depth article:
• There's more fine-grained access control with properties. Need it to be publicly gettable but really only want it set with protected access? No problem (from C# 2 onwards, at least).
• Want to break into the debugger whenever the value changes? Just add a breakpoint in the setter.
• Want to log all access? Just add logging to the getter.
• Properties are used for data binding; fields aren't.
Few other points:
1) You can also make properties read-only so no one from outside the class set the values but can fetch it.
2) You can do certain actions in the get and set. i.e. Append a prefix anytime set is called
3) You can also use auto-implemented property to minimize code like below:
Public Property Name As String
You are not doing anything wrong. Properties give you a shorthand basically, a syntactic sugar.
You can still use a backing private variable and do logic in get and set if you have to while using properties. Even better is the private/protected set or get, which is again another syntactic sugar so that you won't have to write all the code manually.
First of all, VB.NET allows you to use this syntax (called shorthand property declaration - I believe since VS 2010):
Public Property Name As String
Not so much different from this (called field declaration):
Public Name As String
Second, Microsoft data binding does not work well with fields. Try this example (see below).
Example. Put a listbox called ListBox1 (default name) and a button called Button1 on an empty form in an empty WinForms project. Replace your form code with this:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim lst As New List(Of clsMyClass)
lst.Add(New clsMyClass)
ListBox1.ValueMember = "Name"
ListBox1.DisplayMember = "Name"
ListBox1.DataSource = lst
End Sub
End Class
Class clsMyClass
Public Property Name As String = "Hello"
End Class
Start the application and notice that a listbox is populated with one entry, Hello. This proves that binding worked correctly. Now replace your property declaration with a field declaration instead. Start your application one more time and notice that a listbox is showing your class type converted to String. It means that your field binding did not work, and default binding was used instead, where DisplayMember is assigned sort of classInstance.ToString().
If you are curious to learn more about what happens behind the scenes, you can put a breakpoint on .DataSource assignment, and see how DisplayMember gets reset or keeps its value depending on whether you are using fields or properties.

Storing variables between pages VB WP8

I have an app that records time as you press a button. So leave office, arrive site, leave site and arrive office. I have created a button that allows the user to input what parts have been used on the job. This takes you to another screen where input takes place. I can pass these variables back to the main page but because I'm using:
NavigationService.Navigate(New Uri("/MainPage.xaml?msg=" & textBox1.Text, UriKind.Relative))
It resets the data that was in main page.
When I use the NavigationService.GoBack(), the data remains.
Is there a way to keep that data when I am navigating away from the main page?
Yes, just keep the data/datacontext/object on App level.
So for example, use an object in App.xaml.vb
Public Shared Property MyBook() As Book
Get
Return m_MyBook
End Get
Set
m_MyBook = Value
End Set
End Property
Private Shared m_MyBook As Book
And in the OnNavigatingFrom event on your page (or even before, wherever you like), save that data
Protected Overrides Sub OnNavigatingFrom(ByVal e As System.Windows.Navigation.NavigatingCancelEventArgs)
App.MyBook = currentBook
End Sub
When navigating back to that page, just check if the App.MyBook is null, if it's not, it means you've cached something before navigating, so just read it and set the current datacontext to it (or however you set your data on the page)
Protected Overrides Sub OnNavigatedTo(ByVal e As System.Windows.Navigation.NavigationEventArgs)
If (App.MyBook Is Nothing) Then
Else
currentBook = App.MyBook
End If
End Sub
(since you shared no relevant code, my implementation is rather abstract, but the main point is - keep it in the App.xaml.cs and save/load it when you need it)
Store the value in a variable at App.xaml.cs. App.xaml.cs stores variable throughout the lifetime of the app. If the value is being used frequently in other classes/pages too, then as an alternative you can either create a singleton or a static class and use it as a manager for these values. Cluttering App.Xaml.cs is not a good choice, if you have many values to store.

Error when trying to access a textbox on a User Control assigned to a public variable - vb.net

I created two user controls with different user interfaces. Depending on a selection the user makes, one of these interfaces will be used in my class. Since I don't know until after the user makes a selection, I cannot declare the user control ahead of time so I created a public variable to later assign the correct user control to.
The error occurs when I try to access a control (textbox) on the user control. However, if I declare the user control without assigning it to the public variable, then I don't get an error. Also, if I were to assign the user control to the public variable as its being declared then I don't get an error either. I really do need to be able to pick between the two user controls though. I don't know what to do. Am I missing something? I appreciate any help.
Public Class VesselData
Public RCAVesselData
Public AOLVesselData
Public Sub New()
If Main.UserSelectedModule = "Arrival on Location" Then
OperatorView = New AOLVesselData 'User Control 1
ElseIf Main.UserSelectedModule = "Running Conventional Anchors" Then
OperatorView = New RCAVesselData 'User Control 2
End If
OperatorView.txtDistanceToFairlead.text = "A" 'THROWS MissingMemberException - Public member 'txtDistanceToFairlead' on type 'AOLVesselData' not found.
Dim Test as New AOLVesselData
Test.txtDistanceToFairlead.text = "A" 'DOES NOT THROW EXCEPTION
End Sub
The problem is that you are accessing a member that doesn't exist. From the code you have posted, of the AOLVesselData and RCAVesselData classes, it looks like the RCAVesselData class does not have a txtDistanceToFairlead member.
If you have a common set of methods/properties you expect both user controls to expose, refactor them into an Interface and have both user controls implement that Interface. That will make it easy to use them interchangeably.
Try using Shared instead of Public when you declare OperatorView. And, like tcarvin said, you might want to turn "Explicit" on (project compile options) or use "Option Explicit".