Results 1 to 18 of 18

Thread: Class/Module Scope

  1. #1

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    7

    Class/Module Scope

    Let's say I have a class which was created using WPF. Then in code I use...

    Code:
    Partial Public Class MyApp
        Label1.Text = "Hello World"
    End Class
    ...Everything works fine above. But if I want to now do the same within a Code Module...

    Code:
    Module LabelChanger
        Label1.Text = "Hello World"
    End Module
    ...Can't be done. It seems the Code Module can't see it.

    So my queston is...how can I make it so Code Modules can access/see any objects which are created using WPF?

    Is there something I can perhaps add to this XAML statement to make it more global so even code modules can see it?...
    Window x:Class="MyApp"

    I'm using Visual Basic 2010 with WPF

    Thanks for any thoughts
    Last edited by dday9; Apr 23rd, 2024 at 09:19 AM.

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,152

    Re: Class/Module Scope

    In your first example, you are setting a property of an object in a partial class. Since it's a partial class, the rest of the class is elsewhere, and includes something very important: The declarations of Label1. After all, Label1 is an object (probably of type Label) and has to be declared and created. You will find that most likely in the constructor for that class, or in a method called by the constructor for the class.

    In your module, where is Label1 declared OR created? The module is all you have. There's no "other part of it" that you aren't seeing, the way there is with the class.

    Partial classes were introduced with FW 2.0 in VS2005. Prior to that, there were no partial classes, and that could create something of a mess. What you'd find would be that the code behind a form had a Region block that contained all the code that the form designer generated automatically. This was a sizeable block, which could be larger than the rest of the code for the form. It would also be the first part of the code behind any form, but it was just code. You could do whatever you wanted to that code, such as move it, edit it, delete it, and whatnot. Some of those actions would be harmless, while other actions would cause the form designer to fail. So you ended up with a large, messy, chunk of code that you weren't supposed to touch unless you knew what you were doing. It wasn't a great design.

    Partial classes may have been included specifically to address this problem, though I don't know whether or not that was the main reason they were added. All that a partial class means is that you can spread the definition of a class across multiple files. That meant that MS could move all the designer generated code out to a different file (in Windows Forms, this would be names FormName.designer.vb, and I forget what the name was under WPF, so it might be the same). Those designer files were just code files like any other, they just had all that messy designer generated code. By default, the .designer.vb files weren't even visible in Solution Explorer, though you just had to press one button to see them. You could still edit them, and you could still break things by editing them incorrectly, but they were tucked away out of sight, so most people would just ignore them.

    The partial class is where all the controls on the form are declared, and will include a method, which is called by the constructor (InitializeComponents), which was generated by the designer, and which creates instances of all the controls along with setting their properties.

    You aren't doing any of that in the module, so Label1 is meaningless. There are ways to make it meaningful, such as creating a method in the module into which you pass the control as an argument, but that is almost never what people end up doing, because it's often more trouble than any possible gain.
    My usual boring signature: Nothing

  3. #3

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    7

    Re: Class/Module Scope

    Thanks for the reply shaggy, much appreciated.

    Yes, the Partial keyword is something I use to break things into separate files which I find managing code useful, but the same thing happens when I don't use 'Partial'. Here is the XAML code that created that class...

    <Window x:Class="MyApp"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Left = "0" Top ="0" Height="1080" Width="1920" WindowStartupLocation="CenterScreen" WindowState="Maximized" xmlns:my="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" WindowStyle = "None" Background="Black" >
    <Grid x:Name="vGrid" Width="1920" Height="1080" Margin="0,0,0,0" >
    <Canvas Name="Canvas_Main">
    <Image Canvas.Left="0" Canvas.Top="0" Height="1080" Name="imgMain" Width="1920" />
    <Button Canvas.Left="1670" Canvas.Top="884" Content="" Height="119" Name="Button3" Width="150" />
    <Button Canvas.Left="1670" Canvas.Top="1004" Content="T E S T" Height="76" Name="Button1" Width="150" />
    <Button Canvas.Left="1820" Canvas.Top="884" Content="[ ]" Height="119" Name="But_SetScreen" Width="100" />
    <Button Canvas.Left="1820" Canvas.Top="1004" Content="Exit" Height="76" Name="Button2" Width="100" />
    <TextBlock Background="#FFEFE9E9" Canvas.Left="10" Canvas.Top="906" Height="24" Name="Label1" Text="" Width="398" />
    <TextBlock Background="#FFEFE9E9" Canvas.Left="10" Canvas.Top="936" Height="24" Name="Label2" Text="" Width="398" />
    <TextBlock Background="#FFEFE9E9" Canvas.Left="10" Canvas.Top="966" Height="24" Name="Label3" Text="" Width="398" />
    <TextBlock Background="#FFEFE9E9" Canvas.Left="10" Canvas.Top="996" Height="24" Name="Label4" Text="" Width="398" />
    <TextBlock Background="#FFEFE9E9" Canvas.Left="10" Canvas.Top="1026" Height="24" Name="Label5" Text="" Width="398" />
    <TextBlock Canvas.Left="10" Canvas.Top="1056" Height="24" Name="Label6" Text="" Width="398" Background="#FFEFE9E9" />
    </Canvas>
    </Grid>
    </Window>

    ...my project is not using any Forms like the vb6 days, instead I'm using WPF. I just wish that any objects created here could be seen within a Code Module as well somehow. I'm used to code Modules being 100% global but not in this case as they are not able to see everything in the project.

  4. #4
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,204

    Re: Class/Module Scope

    Quote Originally Posted by TRS-80 View Post
    Thanks for the reply shaggy, much appreciated.

    Yes, the Partial keyword is something I use to break things into separate files which I find managing code useful, but the same thing happens when I don't use 'Partial'. Here is the XAML code that created that class...

    ...my project is not using any Forms like the vb6 days, instead I'm using WPF. I just wish that any objects created here could be seen within a Code Module as well somehow. I'm used to code Modules being 100% global but not in this case as they are not able to see everything in the project.
    Your expectations are flawed. A Module needs to be looked at as completely isolated code. So, unless something is declared in the Module, the Module doesn't know about it.

    If you want code in a Module to do something with an external object, you need to pass a reference to that object to the code in the Module.

    Like this air code:

    Code:
    Module LabelChanger
        Public Sub SayHello (LabelToChange As Label)
            LabelToChange.Text = "Hello World"
        End Sub
    End Module
    then you would call this code appropriately from your WPF window like this:

    Code:
    LabelChanger.SayHello(Label1)
    That being said, if you simply want code isolated in individual files, then using a partial class file is tremendously more advantageous. Because it is part of the class, it DOES have visibility to all objects on your WPF surface without any extra leg-work.

  5. #5

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    7

    Re: Class/Module Scope

    Thanks for the reply OptionBase1...
    You mentioned "So, unless something is declared in the Module, the Module doesn't know about it"
    All my data is global through use of Structures or publicly declared variables and all modules can see and work with them just fine. Many things don't need to be passed.
    It's been a while but I think if I placed 'Label1' on a Win Form my Code Module would have no problem seeing and working with it. Doesn't seem to be the case with a WPF 'Form' (for lack of a better word) or should I say 'Canvas'.

    WPF just doesn't seem as integrated into VB as I would like, but that's life I guess. I have no use for a 'class' structure but it's forced through the use of WPF so I have to deal with it I guess. I am simply going to do a work around this to get things where I want.

    Thanks for the replies.

  6. #6
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,204

    Re: Class/Module Scope

    Quote Originally Posted by TRS-80 View Post
    It's been a while but I think if I placed 'Label1' on a Win Form my Code Module would have no problem seeing and working with it.
    Nope, it would not work. In fact, that didn't even work with VB6.

    Yes, the module can have visibility into "globally declared objects". The problem is, no WinForm or WPF contained objects are declared as global objects (by default anyway). They exist as members of their respective class, but a module is not a member of that class.

    This comes up frequently. "Hey, I want to clean my code up and just add it all to a module, it'll be much easier to maintain!" Nope.

  7. #7
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,204

    Re: Class/Module Scope

    Example from VB6: Place a Command Button on the Form, add a Module to the project.

    Form code:

    Code:
    Private Sub Command1_Click()
      Module1.ShowButtonCaption
    End Sub
    Module1 Code:

    Code:
    Public Sub ShowButtonCaption()
      MsgBox Command1.Caption
    End Sub
    Result on MsgBox line: Run-time error '424'. Object required.

  8. #8
    PowerPoster
    Join Date
    Nov 2017
    Posts
    3,204

    Re: Class/Module Scope

    Working example from VB6: Place a second Command Button on the Form, add a Module to the project.

    Form code:

    Code:
    Private Sub Command2_Click()
      Module1.ShowButtonCaptionWorking Command2
    End Sub
    Module1 Code:

    Code:
    Public Sub ShowButtonCaptionWorking(c As CommandButton)
      MsgBox c.Caption
    End Sub
    Result: MsgBox says "Command2", as expected.

    The difference is, the working module subroutine was passed a direct reference to the object that is being accessed. Then it can interact with it.

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,152

    Re: Class/Module Scope

    Even in VB6, you would have had to decorate Label1 in some fashion. After all, form1 can have a label1 and form2 can have a label1. If you could just write Label1.Text = "Blue" in a module, what would you be expecting it to do? Would it have to look through every object in the project looking for objects that contained a member called Label1 that had a settable .Text property? That would be horrible, and it still wouldn't be adequate, because the project might reference dlls, and those might contain an object that had such properties.

    Most likely, in VB6, you were decorating the label with something like Form1.Label1.Text. You could do the same thing in WinForms .NET....but you most definitely should NOT. That would be making use of the default instance of the form, and doing so can cause all kinds of fun side effects. We used to get numerous threads on here because of the confusion that caused. Default instances just aren't used all that much, anymore.

    In WPF, things are only slightly different. You have your XAML, yes, but you also have a class behind that for each page/form. Somewhere in that class is a method called InitializeComponent(). It will be found in the constructor, but you may not SEE the constructor, by default. You only see a constructor if you write one. If you don't write one, then VS generates one for you, and generates the InitializeComponent() method. If you write your own constructor, you will get the InitializeComponent method automatically added, with a comment above it saying 'This call is required by the designer.

    It really is, too. If you delete that method call, you won't have a form at all. What the method is doing is taking your XAML and using it as instructions to create the controls used on the form/page. Those controls are objects. You have to create an instance of an object before you can use it, and that's what InitializeComponent is doing.

    You can then get access to those controls or components outside of the class that created them, but that follows the same scoping rules as any other member of any class would. None of them are global. You could make global references to them, but it would be a pretty bad idea. Not a horrid idea, but one that you would end up regretting sooner or later (probably sooner).

    The controls are much harder to track down in WPF, but they are there. You can find them by looking at Me.Content and drilling down through the children. At some level, you will encounter things derived from Control, but you might be drilling down three or four levels. WPF has some complexity due to making it very versatile.
    My usual boring signature: Nothing

  10. #10

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    7

    Re: Class/Module Scope

    "Most likely, in VB6, you were decorating the label with something like Form1.Label1.Text. You could do the same thing in WinForms .NET..."

    Yes, that's how I used to do things in vb6. within a code module I just had to place "Form1" in front and all works perfectly, intuitively ,all good. I would have let's say 10 forms all differently named "frmMain, frmSettings, frmInput, etc. and all I have to do when it comes to doing anything with an object on any form ANYWHERE in my program including modules, is just place the form name in front of the object...frmMain.Label1.Caption = "Welcome", frmSetting.Label1.Caption = "Off", etc. Simple and clean. If I could do that same thing except instead of using a form to place things on screen, I'm using a WPF canvas and placing objects on that, would be terrific.

    I'm going to try some things during runtime and try not to have any objects in the XAML code and simply create them during runtime. I mean, I do create thousands of them during runtime and all is fine, I'm going to try and get everything fully accessible. Going to have a good relook at it all.

  11. #11

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    7

    Re: Class/Module Scope

    Also, when it comes to all the objects in my App. I use this...

    I create many controls and simulate control arrays (adding X, Y, Z to its Tag property) wonderfully and they perform great and have no complaints (yet). I use this first to create the object(s) on a WPF Canvas of my choice...
    "RegisterName(Obj.Name, Obj)" ... WinRT didn't require this, seems I need it in Visual Basic 2010 though.

    Then to later access/manipulate that object I use this...
    Dim Obj As Object = FindName(ObjName)

    I was concerned a little by this approach performance wise. I test all code with a high resolution timer and so far it's just a few milliseconds (I love machines now a days. I prefer direct access to an object instead of asking the machine to search (yuk), but the speed is impressive.

    I don't think I can get rid of/replace this...
    <Window x:Class="MyApp"
    </Window>
    ...but I will try to make reference to all objects on a WPF canvas without it having to be wrapped within a 'class'.

  12. #12
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,152

    Re: Class/Module Scope

    Simple and clean, yes, but only simple if the program itself was simple. After all, if you have frmMain, then that is a type, not an instance of the type. I hesitate to make any sweeping statements about VB6, as it has been a LONG time since I used it, and people on here would gleefully correct me if I get something wrong, but VB6 always created an instance of any form type, which blurred the line between types and instances. I used to do the same thing you did.

    In VB.NET WinForms, the same thing was possible, but it was because a line of code similar to this was quietly created for you:

    Public frmMain = New frmMain

    In other words, so long as you had a constructor that took no arguments, an instance of the form was created with the same name as the type. This was the default instance. It caused trouble with threading, and caused endless confusion when people showed a different instance, then tried to reference the default instance. The code would work fine, but since the default instance was different from the one they showed, any changes made to the visible form wouldn't be accessible to them.

    What I never did do in VB6 was create multiple instances of a form...or at least, I don't remember doing that, and I don't recall how it was done, though I think it was possible. Had you done so, and created two instances of frmMain, how would you keep them straight?

    What was done in VB6 was based on what was easiest for a simple program, while making it much more difficult if the program didn't match that simple model. In .NET, what was done was in some ways more fundamental: A form is just a definition of a thing. You can then create as many instances of that thing as you want. Once you do that, keeping track of which instance you are working with becomes a problem. It's a decidedly solvable problem, but it's still a problem. MS tried to make VB.NET familiar to Vb6 by saying, "you can create as many instances as you want, but THIS one is special." That confused people.

    In theory, you could do nearly the same thing with a Dictionary created in a module, but it depends a bit on why. Your example has just been with a label, which is probably not what you are actually wanting to do. A Dictionary would require a tiny bit of maintenance for it to work well, but even that tiny effort wouldn't be justified if you were doing the same for every control.

    The bottom line is that this is just a difference. VB6 was simple for a specific type of program (one instance per form), not so simple if that type wasn't followed. The goal of .NET was the same level for all types. It's a difference....but of course, you're working with WPF, which is seriously different already.
    My usual boring signature: Nothing

  13. #13
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,152

    Re: Class/Module Scope

    Quote Originally Posted by TRS-80 View Post
    Also, when it comes to all the objects in my App. I use this...

    I create many controls and simulate control arrays (adding X, Y, Z to its Tag property) wonderfully and they perform great and have no complaints (yet). I use this first to create the object(s) on a WPF Canvas of my choice...
    "RegisterName(Obj.Name, Obj)" ... WinRT didn't require this, seems I need it in Visual Basic 2010 though.

    Then to later access/manipulate that object I use this...
    Dim Obj As Object = FindName(ObjName)

    I was concerned a little by this approach performance wise. I test all code with a high resolution timer and so far it's just a few milliseconds (I love machines now a days. I prefer direct access to an object instead of asking the machine to search (yuk), but the speed is impressive.

    I don't think I can get rid of/replace this...
    <Window x:Class="MyApp"
    </Window>
    ...but I will try to make reference to all objects on a WPF canvas without it having to be wrapped within a 'class'.
    If you don't want to search, consider a Dictionary (of String, SomeControl). You could make that dictionary in a module, add every control to it at once, keyed on whatever name you want, and then getting to a control would be:

    YourDictionary("YourControlName").WhateverPropertyYouWant

    Dictionary lookups are super fast, so this would likely be quite a bit faster than your .Tag approach, and it leaves the .Tag available for other uses.
    My usual boring signature: Nothing

  14. #14
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,152

    Re: Class/Module Scope

    Ultimately, though, you are fighting to fit the world into your mental model, rather than changing your mental model to fit the world. In .NET (as in most programming languages these days), ALL code is in a class. It can't be otherwise, no matter how hard you try. Even a Module is a class, since it's turned into a Class with all Shared members. There is only one real difference between these two:
    Code:
    Module MyMod
     Public MyObject As Object
    End Module
    
    Public Class MyClass
     Public Shared MyObject As Object
    End Class
    The difference is that for the former, you can write:

    MyObject

    whereas for the latter you need to write:

    MyClass.MyObject

    This difference has nothing to do with the language, either. It's some syntactical sugar that MS added to VB.NET so that a module in VB.NET felt more like a module in VB6. Under the hood, they are the same thing in every way.
    My usual boring signature: Nothing

  15. #15

    Thread Starter
    New Member
    Join Date
    Apr 2024
    Posts
    7

    Re: Class/Module Scope

    "Ultimately, though, you are fighting to fit the world into your mental model, rather than changing your mental model to fit the world."

    Yes! That's a bullseye right there It's how I've always done things and it sure is a lot of work but worth it, can always find a way. Take databases for example, recently I wrote a custom one (again) that stores data down to the bit level with no regard for datatypes, very nice system without any waste ready to send over the network. It took a ton of creative coding but a lot of the hard work was getting around how 'on rails' microsoft coding has become. Who knows, maybe MS coding will get to such a high level we'll call them authoring systems. So much MS 'stuff' I need to work around, undo and subdue to get something working the way I want.

    The main reason I'm looking for a solution to this scope issue is further down the rabbit hole I don't want to take you guys down. You'll just call the cookie truck on me I have a simple enough solution that will do for now until something perfect comes along.

  16. #16
    Addicted Member
    Join Date
    Jul 2022
    Posts
    247

    Re: Class/Module Scope

    *** off topic *** love the name, it made me actually lol

  17. #17
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    39,152

    Re: Class/Module Scope

    I wouldn't say I laughed. I had one of those. I barely remember it, but that's fair, since it barely had any memory either.
    My usual boring signature: Nothing

  18. #18
    Addicted Member
    Join Date
    Jul 2022
    Posts
    247

    Re: Class/Module Scope

    Quote Originally Posted by Shaggy Hiker View Post
    I wouldn't say I laughed. I had one of those. I barely remember it, but that's fair, since it barely had any memory either.
    HAHAHA that was more than a bit funny

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width