How to select an image from resources via a string? - vb.net

I'm coding a pokedex type deal as practice for my class.
Basically, I have a class titled "pokemon". One of the properties of the class is "ImgName" Which I want to use to display an image from the resources with the same name.
VB doesn't allow me to call the ImgName as a string and then use 'My.Resources.ImgName'
How can i do this, or what are some alternative options to it? I want it to be determined by a property in the pokemon object, and i don't want to have to hard code in an if-elseif statement for every single pokemon.

One way is you can have a resource file added to your project. Then drop the resource into it. You will be able to address it like this:
My.Resources.Resource1.ImgName
Resource1 is your resource file name, and ImgName is the resource name here. But you need to do hard code for every call. However, you get full intellisense support with type checking.
If you don't want hard code, here is a stripped down version of my production code:
Imports System.Reflection
Imports System.Xml.Linq
Public Class EmbeddedResourceManager
Private Class EmbeddedResourceManagerCore
Private Shared _executingAssembly As Assembly
Private Shared _resourcePrefix As String
Shared Sub New()
_executingAssembly = Assembly.GetExecutingAssembly
_resourcePrefix = _executingAssembly.GetName.Name & "."
End Sub
Public Shared Function GetStream(resourceRelName As String) As IO.Stream
Return _executingAssembly.GetManifestResourceStream(_resourcePrefix & resourceRelName)
End Function
End Class
Public Shared Function GetImage(ByVal resourceName As String) As Bitmap
Return New Bitmap(EmbeddedResourceManagerCore.GetStream(resourceName))
End Function
End Class
So whenever you need, just call EmbeddedResourceManager.GetImage and pass the resource name, as it appears in your project (your image file needs to be attached to a project). You need to have Build Action for an image in question to be set to Embedded Resource.
This piles up all your resource into an executable, which has both benefits and drawbacks, depending on the situation. Still, it should work for your needs, since I am assuming number of different pokemons is limited and does not change throughout the game (i.e. downloaded from a 3rd party server in real time etc.).

BackgroundImage = My.Resources.ResourceManager.GetObject(aString)
10 time easier than previous answer imho

Related

Accessing an object over class

When reading an old project of mine I found something suspicious where I don't really understand why this part is working:
Public Shared Sub getXMLforProject(QueryString As String)
Dim linkStart As String = "http://example.org"
Dim linkEnd As String = "&tempMax=2000"
Dim target As String = linkStart & QueryString & linkEnd
'replaces parts that need encoding,
'groups(1) is the sign e.g. <= and groups(2) is the text that needs encoding
'groups(0) is the text of the full match (sign and encoding text)
target = rx.Replace(target, Function(m As Match) encodeURLString(m.Groups(1).Value) + encodeURLString(m.Groups(2).Value))
GUI.WebBrowser.Navigate(target)
Return True
End Sub
the respective path that seams suspicious to me is the line
GUI.WebBrowser.Navigate(target)
There is a class called GUI that realises the user interface, but in the file context there is no objects named "GUI" available, so the access must be done by using the class. How is it possible for this to work? Is there an implicit mechanism that redirects the call from the GUI-class to the GUI-object?
You are using VB.NET, it emulates the behavior of the Form class from earlier Visual Basic editions where using the type name was a legal way to refer to an instance of the class. Kinda necessary to give programmers a fighting chance to convert their VB6 projects. Underlying plumbing is the My.Forms object.
So, 99.9% odds are that the GUI class derives from System.Windows.Forms.Form. Especially given that it has a WebBrowser member. The Form is the host window for the browser.

.net load configuration in class library

let's say i have :
1) 1 WindowsForm on "A" Project
2) 1 WindowsForm on "B" Project
3) 1 class library (GAC)
Condition
Both of Project references is same
Part 1 :
I have my.settings in my class library to save configuration with public function
Part 2 :
I create value/configuration from "A" and store it in my class library.
settings has been successfully saved, and load the value/configuration with no errors
Question :
1). Why i can't load the value/configuration from "B" ? NullException shown
First I think, to use my.resources in class library but, my.resources is readonly
2). What best solution to connecting 1 class library to multiple project
code in class library to save value
Public Sub Kucing_simpan(ByVal value As String)
My.Settings.Kucing = value
My.Settings.Save()
End Sub
code in class library to load value
Public Function kucing_ambil()
Dim value As String
value = My.Settings.Kucing
Return value
End Function
code in "A"
dim save as new Zombie.Kencing 'My class Library Name
save.Kucing_simpan(textbox1.text)
code in "B"
dim load as new Zombie.Kencing 'My class Library Name
DataGridView1.Rows(0).Cells(1).Value = load.kucing_ambil
You cant do what you are trying to do - at least not the way you are going about it.
First, you have to understand how/where Settings are saved. With default naming of the app and such, project A - WindowsApplication1 will save its settings to something cryptic such as:
C:\Users\<UserName>\AppData\Local\Microsoft\_
WindowsApplication1_Url_ggn13vigzyicmtfkwaa3vi5tyxn0sy3r\1.0.0.0\user.config
NET creates the hash to make sure that apps with the same name have a different safe location to store settings. So, WindowsApplication3 will have a different hash; this is also how your 17th project with the name WindowsApplication1 doesnt accidentally load or find the settings of WinApp 1-16.
Next, your Settings Class Lib is not a separate application. As a DLL, it is operating as if it was a set of functions and such associated with the App calling it. So when Project A saves settings thru the ClassLib, they are saved to a different location than Project B. Even using a Class Lib, NET uses Application credentials and info to concoct the filename and path.
What you can do is write a Class which defines all the possible settings (or creates a List or Dictionary of them) then save to a fixed, known location such as:
Private Comp As String = "ZiggySoft"
Private Prod As String = "ZiggyWare"
Private settingsFile As String
'...
settingsfile = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
settingsfile = Path.Combine(settingsfile, Comp, Prod, "usersettings.dat")
This will result in:
"C:\Users\\AppData\Roaming\ZiggySoft\ZiggyWare\usersettings.dat"
Include the same file in each project (Add Existing Item, maybe pick Add As Link from the dropdown). Now, you can read and write your Settings to a file you are in charge of. You can save/load the entire class or List in 3-5 lines of code if you serialize it.
When Project A loads the settings, it would also get those which only apply to B or J or V, but common ones would and could be shared.

Is there a way to determine the value of a property on a form that calls a method in a seperate class library

Specifically aimed at winforms development.
I suspect that the answer to this is probably No but S.O. has a nice way of introducing me to things I didn't know so I thought that I would ask anyway.
I have a class library with a number of defined methods therein. I know from personal experimentation that it is possible to get information about the application within which the class library is referenced. What I would like to know is whether it would be possible to get information about the value of a property of a control on a form when a routine on that form calls a method in my class library without passing a specific reference to that form as a parameter of the method in the class library?
So purely as an example (because it's the only thing I can think of off the top of my head). Is there a way that a message box (if it had been so designed to do so in the first place) could 'know' from which form a call to it had been made without that form being specifically referenced as a parameter of the message box in the first place?
Thanks for any insights you might have.
To address the example of the MessageBox, in many of the cases you can use the active form. You can retrieve it by using Form.ActiveForm. Of course, as regards the properties that you can request, you are limited to the properties provided by the Form or an interface that the Form implements and that the method in the other assembly also knows. To access other properties you can use Reflection, but this approach would neither be straightforward nor would it be clean.
In a more general scenario, you could provide the property value to the method as a parameter. If it is to complex to retrieve the value of the property and the value is not needed every time, you can provide a Func(Of TRESULT) to the method that retrieves the value like this (sample for an integer property):
Public Sub DoSomethingWithAPropertyValue(propValFunc As Func(Of Integer))
' Do something before
If propertyValueIsNeeded Then
Dim propVal = propValFunc()
End If
' Do something afterwards
End Sub
You call the method like this:
Public Sub SubInForm()
Dim x As New ClassInOtherAssembly()
x.DoSomethingWithAPropertyValue(Function() Me.IntegerProperty)
End Sub
I kind of question your intentions. There's no problem sending the information to a function or the constructor.
Instead of giving the information to the class, the class would ask for the information instead using an event.
Module Module1
Sub Main()
Dim t As New Test
AddHandler t.GetValue, AddressOf GetValue
t.ShowValue()
Console.ReadLine()
End Sub
Public Sub GetValue(ByRef retVal As Integer)
retVal = 123
End Sub
End Module
Class Test
Public Delegate Sub DelegateGetValue(ByRef retVal As Integer)
Public Event GetValue As DelegateGetValue
Public Sub ShowValue()
Dim val As Integer
RaiseEvent GetValue(val)
Console.WriteLine(val)
End Sub
End Class

How to prevent VBA variables from being shared across Word documents?

I have a VBA template project that runs automatically when a Word document is opened. However, if I open multiple documents, they all share the variables values. How can declare these variables to be only associated with the active window or active document?
I tried declaring them in a Class Module, but that did not help. Switching between opened document I can see that these variables are shared.
Any input is appreciated...
This what I have in my Module:
Option Private Module
Dim CurrentCommand As String
Public Function SetCurrentCommand(command)
CurrentCommand = command
End Function
Public Function GetCurrentCommand()
GetCurrentCommand = CurrentCommand
End Function
More Info: The code/Macro start at AutoExec like this:
Public Sub Main()
Set oAppClass.oApp = Word.Application
If PollingRate <> "" Then Application.OnTime Now + TimeValue(PollingRate), "CaptureUserViewState"
End Sub
And the CaptureUserViewState is a Sub that resides in a different Module and does all teh checks (comparing new values to last recorded ones) and here how this Sub does the check:
If WL_GetterAndSetter.GetLastPageVerticalPercentage <> pageVerticalPercentScrolled Then
'Update the last value variable
WL_GetterAndSetter.SetLastPageVerticalPercentage (pageVerticalPercentScrolled)
'log change
End If
You don't give us much information, but I assume you declared public variables at module level like this:
Public myString As String
Public myDouble As Double
From VBA documentation:
Variables declared using the Public statement are available to all procedures in all modules in all applications unless Option Private Module is in effect; in which case, the variables are public only within the project in which they reside.
The answer is to use Option Private Module.
When used in host applications that allow references across multiple projects, Option Private Module prevents a module’s contents from being referenced outside its project.
[...] If used, the Option Private statement must appear at module level, before any procedures.
EDIT You have now clarified that you declare your variables using Dim at module level. In this case, Option Private Module is irrelevant.
Variables declared with Dim at the module level are available to all procedures within the module.
i.e. regardless of whether you're using Option Private Module or not.
If you're finding that the values are retained between runs, then that must be because you are running a procedure from the same module from the same workbook. You may think you're doing something else, but in reality this is what you're doing.
EDIT
In your class module, instead of Dim CurrentCommand As String try Private CurrentCommand As String. Without more information it's hard to debug your program. I'm just taking random potshots here.
What you need to do is store multiple versions of the variables, one set per document.
So I would suggest that you create a simple class to hold the different values.
You then store them in a collection mapping the data-set with the document name or similar as the key.
In classmodule (MyData), marked as public:
Public data1 as String
Public data2 as Integer
In module with the event-handlers:
Dim c as new Collection 'module global declaration
Sub AddData()
Dim d as new MyData 'Your data set
d.data1 = "Some value"
d.data2 = 42
c.add Value:=d, Key:=ActiveDocument.name
End Sub
Then when you enter the event-handler you retrieve the data and use the specific set for the currently active document.
Sub EventHandler()
Dim d as MyData
set d = c.item(ActiveDocument.name)
'use data
'd.data1...
End Sub
Please not that this code is just on conceptual level. It is not working, You have to apply it to your problem but it should give you some idea on what you need to do. You will need to add alot of error handling, checking if the item is already in the collection and so on, but I hope you understand the concept to continue trying on your own.
The reason for this is because, as I understand the situation from your question, you only have one version of your script running, but multiple documents. Hence the script have to know about all the different documents.
On the other hand, If each document would have their own code/eventhandlers, hence having multiple versions of the script running, then you don't need the solution provided above. Instead you need to be careful what document instance you reference in your script. By always using "ThisDocument" instead of "ActiveDocument" you could achieve isolation if the code is placed in each open document.
However, as I understood it, you only have one version of the script running, separate from the open documents, hence the first solution applies.
Best of luck!
You might want to store the Document Specific details using
The Document.CustomDocumentProperties Property
http://msdn.microsoft.com/en-us/library/office/aa212718(v=office.11).aspx
This returns a
DocumentProperties Collection
Which you can add new Properties to Using
Document.CustomDocumentProperties.Add(PropertyName, LinkToContent, Value, Type)
And then Read From using
Document.CustomDocumentProperties.Item(PropertyName)
A downside, or bonus, here is that the properties will remain stored in the document unless you delete them.
This may be a good thing or a bad thing

Change connection string from class library in main application at run-time

You can change the connection string at run-time like this. You make the connection string setting available for writing as a separate property inside the MySettings class:
Partial Friend NotInheritable Class MySettings
Public WriteOnly Property RunTimeConnectionString()
Set(ByVal value)
My.Settings("MyConnectionString") = value
End Set
End Property
End Class
Then, in some place when the application is being initialized (before using any table adapters of typed datasets), write something like:
My.Settings.RunTimeConnectionString = My.Settings.ProductionConnectionString
Where ProductionConnectionString is a simple String setting. It is a User Scope setting so every user can change it (by assigning a value to it, similar to the code above) and save it by calling My.Settings.Save()
This code works well for connection strings which were initially created in the main project and stored in it's settings (= app.config file).
The connection string in the app.config actually has a longer name: MyApp.MySettings.MyConnectionString.
When you have a connection string stored in the app.config in a class library project, and reference that project in the main project, the app.config files will somehow be merged, so the class library has it's settings.
The thing that don't know how to do, is change a setting from the class library at run-time. I could copy the connection string setting from the class library to the main project's app.config. I must keep the same name, which looks something like: MyClassLibrary.My.MySettings.MyConnectionString.
Can the same principle I showed above be somehow applied to this second connection string?
I tested a little more, and found out that the same solution can be used inside a class library.
I made a new class (in the class library) with a shared (static) method like this:
Public Class MySettingsChanger
Public Shared Sub SetConnectionString(ByVal cnnString As String)
My.Settings.RunTimeConnectionString = cnnString
End Sub
End Class
And extended the MySettings class (in the class library) the same way as in the main project:
Namespace My
Partial Friend NotInheritable Class MySettings
Public WriteOnly Property RunTimeConnectionString()
Set(ByVal value)
My.Settings("MyConnectionString") = value
End Set
End Property
End Class
End Namespace
At least it works in my case. The name of the connection in the main project and in the class library is the same only (the short name, not the whole ProjectNamespace.MySettings.ConnectionName). I haven't tested with having a different name of the connection in the class library, but think it should not matter.
I searched more, and found a way, but it isn't really runtime. At least not as runtime as I would like it to be. Anyway, here is the code, I tested it and it worked, but required me to restart the application first. That's not very runtime to me.
Dim configLocation As String = Reflection.Assembly.GetExecutingAssembly().Location
Dim config As Configuration.Configuration = Configuration.ConfigurationManager.OpenExeConfiguration(configLocation)
config.ConnectionStrings.ConnectionStrings.Clear()
For i As Integer = 0 To Configuration.ConfigurationManager.ConnectionStrings.Count - 1
Dim connection As New Configuration.ConnectionStringSettings(Configuration.ConfigurationManager.ConnectionStrings(i).Name, My.Settings.ProductionConnectionString)
connection.ProviderName = Configuration.ConfigurationManager.ConnectionStrings(i).ProviderName
config.ConnectionStrings.ConnectionStrings.Add(connection)
Next
config.Save()
This is the article where I found this code.
Thanks for the message on the blog. Yes, it is hardly run-time as it requires you to stop running for the changes to be picked up. Unfortunately, because settings are loaded once and only once (when the app domain is loaded), there isn't a way for the settings infrastructure to pick up changes while running.
The only option is to either restart the app or recyle the app pool if a web application. Beyond that, you would have to roll your own.
I did the best I could :-)