Click here to Skip to main content
15,890,609 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
The following is supposed to run after
VB.NET
TwoSecondTimer.Enabled = True
is executed in my Public Class Root right?
VB.NET
Public Module Timers
    Public WithEvents TwoSecondTimer As New Timer With {.Interval = 2000}
    Sub TwoSecondTick() Handles TwoSecondTimer.Tick
        Root.AddToMessages("tick")
        Root.AddToMessages(Main_Window.Cash)
        Main_Window.Cash += Main_Window.Income
        Main_Window.CashLbl.Text = "¤ " & FormatNumber(Main_Window.Cash)
    End Sub
End Module


Thing is the timer is not enabling when told to. Even if enabled by default, the timer code still doesn't work anyway...

...Root.AddToMessages works, but the two lines involving Main_Window don't. Root is my first form, Main_Window is one of the forms being instantiated through reflection. There are no errors during runtime, the Cash variable just doesn't change from it's default value and CashLbl.Text never changes.

Edit:
So the timer can't be enabled from my Root class and Main_Window controls/variables can't be modified from my Timers Module. What am I forgetting?

If I modify my code in ways necessary to change TwoSecondTimer and TwoSecondTick to be Shared, then I get the error NullReferenceException.

The previous was solved by changing Forms.Timer to Timers.Timer, since the timers were created in a module instead of on a form.

Note, the forms are created as such:
C#
Dim NewWindow As Form = CType(Activator.CreateInstance(Type.GetType(AssemblyData.GetName & "." & sender.text.replace(" ", "_"), True, True)), Form)


So if a reference to the newly created instances of Main_Window is needed, how could I create one and link it with a form in order to manipulate the form?
Posted
Updated 26-Jan-16 13:21pm
v6
Comments
Sergey Alexandrovich Kryukov 24-Jan-16 19:39pm    
Is it System.Timers.Timer? Did you call Timer.Start? Why using a timer at all? Did you consider using a separate thread instead, which is less dangerous? Do you use any UI in a timer tick handler? If you do, you need to use Invoke or BeginInvoke, methods of System.Windows.Forms.Control (for Form applications only) or Dispatcher's methods.
—SA
ChaosOverlord_ 25-Jan-16 2:23am    
It's not, turns out changing to a system.timers.timer was indeed a solution to one of my problems, thanks!

Invoking has no effect (even after testing it anyway, invoking just isn't required)

Since Main_Window has a new instance of itself being created during runtime, could it be that modifying a variable or control within Main_Window (ex. Main_Window.CashLvl.Text = "xxx") is actually trying to reference a previous instance instead of the newly created one?

If so, would adding NewWindow into a global public collection (ex. Public CreatedForms as FormCollection) allow me to reference this new instance, or would it be better to attempt to reference the form through Application.OpenForms?
Sergey Alexandrovich Kryukov 25-Jan-16 9:33am    
Do you mean that InvokeRequired returns false?
Messed up references could only be possible if you mess them up yourself... :-)
—SA
ChaosOverlord_ 25-Jan-16 18:00pm    
Yes InvokeRequired is false.

I'm not sure how I could have messed up though. In my code I'm directly calling Main_Window. Since multiple instances of Main_Window can exist at once, I suppose I need to reference an instance in particular but I don't know how to do that.
Sergey Alexandrovich Kryukov 25-Jan-16 18:31pm    
I don't understand the problem with reference. It's up to you to provide a reference. Is it a problem of collaboration between different form/window instances? It's a pretty simple stuff. And again, what's the goal of bi-second events?
—SA

Which Timer are you using? If it's the System.Windows.Forms.Timer it has to be placed on a Form in order to work.
 
Share this answer
 
Comments
ChaosOverlord_ 25-Jan-16 2:25am    
Good solution, this fixed my timer problem so thanks, unfortunately this was only a secondary issue.

My main problem remains I am unable to manipulate newly created instances of forms during runtime.
Dave Kreskowiak 25-Jan-16 7:58am    
Your code seems to assume that Root and Main_Window are "global" variables defined elsewhere.

Code like this usually sits on the form that has these forms or controls defined in it, not in a separate module.
ChaosOverlord_ 25-Jan-16 18:15pm    
Root and Main_Window are both classes (which both do have their own forms if that isn't obvious already)

Tried to move them into a module to make my program more organized since it will become quite large. I had already tried moving the relative pieces of code from the module into the respective form to no avail.

Basically what is revealed by this is that there are indeed new instances of Main_Window being created any time it's opened, so basically I am wondering how to reference those newly created instances. Adding some temporary diagnostic code shows that there are multiple 'Main_Window's active if I open more at runtime, so calling for a variable from outside of Main_Window (by using Main_Window.Cash in my Root class) will only return the *first* instance's Cash variable.
Dave Kreskowiak 25-Jan-16 18:59pm    
This is why any code that interacts with a form belong in the forms code, not in a module.

I don't have enough information to tell you what's going on and how to do something. All I can see is the tiny code snippet in your original post.
ChaosOverlord_ 25-Jan-16 20:26pm    
"I had already tried moving the relative pieces of code from the module into the respective form to no avail."
---------------
"Dim NewWindow As Form = CType(Activator.CreateInstance(Type.GetType(AssemblyData.GetName & "." & sender.text.replace(" ", "_"), True, True)), Form)"

As in shown my question, this is the code creating new instances of the Main_Window form.

Attempting to call/manipulate controls and variables belonging to Main_Window from my Root class is not referencing the instance of Main_Window that I am attempting to manipulate.
ChaosOverlord wrote:

Ah, so if I am to create a lot of different controls, then there is no way of avoiding a large amount of code to create all of the controls?
Also, if these controls are better to be created locally, then what is the best way to call these controls from other subroutines or classes?
Wrong. The number of controls is not translated into amount of code. You avoid large amount of code by abstracting out common functionality of different controls and other elements. Your code is only as complicated as different algorithms are. If you use the same algorithm for many controls, the number of them is majorly absorbed. You have to spot common elements of behavior and never ever repeat yourself. Please see: Don't repeat yourself - Wikipedia, the free encyclopedia[^].

—SA
 
Share this answer
 
ChaosOverlord_ wrote:

VB
Dim NewWindow As Form = CType(Activator.CreateInstance(Type.GetType(AssemblyData.GetName & "." & sender.text.replace(" ", "_"), True, True)), Form)
I need to summarize the reflection issue and the misconception you have here.

Let's say, by the moment your execution enters the entry point (Main) method during runtime, your whole process have N .NET types loaded. You only need reflection only at the moment you need to introduce the type number N+1 during (the same) runtime. Then you have the such options as 1) load another assembly developed separately, 2) create an assembly by compiling it in the same process using CodeDOM, 3) dynamically create a new assembly using System.Reflection.Emit.

Despite my all my effort, you never mentioned such need. All your considerations were about using the same N types. You cannot use them more "dynamically", because, with fixed set of type, instantiating them with constructors is already as dynamic as it can be. So, from this moment, forget Activator, until you really need reflection or System.Reflection.Emit.

—SA
 
Share this answer
 
Comments
ChaosOverlord_ 27-Jan-16 4:19am    
This version of the explanation is much clearer thanks.
Sergey Alexandrovich Kryukov 27-Jan-16 10:30am    
You are welcome. Are you going to accept this or some answers formally?
—SA
ChaosOverlord_ 27-Jan-16 19:42pm    
Most of the answers to my problem were in comments spread throughout all the proposed solutions, some proposed solutions themselves were helpful but didn't fully answer my primary dilemma...I'm not sure what the most proper way to handle this would be.

This solution (#4) is the best among current solutions available because it explains how my original technique *was* the problem, however the real solution can only be deduced after taking into consideration all of the comments spread throughout this question.
Sergey Alexandrovich Kryukov 27-Jan-16 20:04pm    
I told you several times: try to explain what you want to achieve. So far, you juggle very fuzzy concepts, such as "manageable". There is no one golden rule. You have to decompose your problem into something discussible.
—SA
By containing the form reference in a global collection such as this;

VB.NET
Public OpenedWindows As New List(Of Form)


The instance can be referenced from anywhere else in the project by searching through the collection and matching the Form.Name with the form you are trying to modify.

A better way of doing this is by using a Dictionary, since you don't have to loop through a collection. Instead, dictionaries allow the use of a key.

VB.NET
Public OpenedWindows As New Dictionary(Of String, Form)

In the dictionary, the form name (or any chosen unique identifier for that matter) is used as a key. Calling the reference and changing a property of the form is then as easy as;

VB.NET
OpenedWindows("Unique Indentifier").Text = "New Title"


If you want to modify a control of the form, the best method is to reference them through the constructor, however if instances are created using other means, then that solution does not apply. If that is the case, either use a similar method of keeping the form's controls in a collection or search through the forms controls until you find what you are looking for.

For Each _Label As Label In OpenedWindows("Unique Indentifier").Controls.OfType(Of Label)
                    If _Label.Name = "TestLabel" Then
                        _Label.Text = "It works!"
                    End If
                Next
 
Share this answer
 
v2
Comments
Sergey Alexandrovich Kryukov 26-Jan-16 19:49pm    
All wrong. You should never use form Name. Why? It makes no sense at all.
Do you really think this is the "solution"? You self-accepted it as solution. Why?
All this "search" will work, of course, only it makes no sense at all.
I would ask you what you ultimately want to achieve (ultimately, that's it; "manipulate controls of a newly created instance of a form" cannot be a goal, it may have some purpose), but I'm not sure you can answer... Will you?
—SA
ChaosOverlord_ 27-Jan-16 0:58am    
I posted as the solution because I tried it and it works. Everything I have been attempting to do is executing as I had hoped. Forms are being created at the click of a button and controls in those forms are being modified.

It isn't the best way of doing it by far I know, but my solution pertains to my particular problem referencing forms created in my particular way.

Ultimately I want to have buttons creating forms and be able to alter those forms from any class, as part of a multi-form UI. I tried to avoid using something as static as a constructor for each form.
Dave Kreskowiak 26-Jan-16 20:02pm    
Uhhh...wow. This is NOT the best way at all. You're making it extremely convoluted (not to mention very slow) to change the Text of a Label control.

Your code is not testable, you've completely destroyed any chance of using interfaces, and you've blown separation of concerns clear out of the water.

You're actually making it harder on yourself, not easier. It may be organized to you, but it's a nightmare for the person coming in behind you to support and modify the code.
ChaosOverlord_ 27-Jan-16 1:09am    
It's not in general no, but it's a solution pertaining to my particular method of instantiating forms. After implementing the solution above, my program was all working as planned.

I actually don't even know what an interface is, which gives you a better idea of where I am in regard to knowledge of the field. I'm no professional by far.

I already know my method is much harder, it's all trying to find a way to make my code as dynamic as possible. Learning through innovation. Purposely avoiding the use of a simple constructor.
Sergey Alexandrovich Kryukov 27-Jan-16 1:12am    
Again, it's all about one thing: you need to explain the ultimate purpose of all this activity. So far, nothing seems to make sense.
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900