Notifications
Clear all

[Closed] dotNet.addEventHandler cannot access struct members?

I鈥檝e got a little problem when using dotNet.addEventHandler within a struct.
For example, I have a function in a struct which creates a System.IO.FileSystemWatcher object. I add an eventhandler to that object, which is a function in the same struct.
This function is called, no problem so far.
However, if I want to do anything with the struct members, that鈥檚 when things fail:

>> MAXScript dotNet event handler Exception: 鈥?Runtime error: Struct member access requires instance: kbd_actions <<

in this case kbd_actions is just a member of the same struct in which the handler is defined (and yes it is defined prior to the handler). When I explicitly point to the instance when adding the handler (which is bad to begin with) the handler isn鈥檛 even executed when the event is fired鈥?/p>

I wonder, is the handler actually operating in global scope or something? What鈥檚 going on here? And more importantly, how do I overcome this?

18 Replies
1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

i don鈥檛 see a problem:


struct formHolder 
(
	form,
	size = [200,270],
	pos = [900,150],
	title = "The Form",
	fn open = (if iskindof form dotnetobject do form.Showmodeless()),
	fn close = (if iskindof form dotnetobject do form.Close()),
	fn onShown s a = 
	(
		print (s.WindowState.toString())
	),
	fn onMove s a = 
	(
		print (s.Location.toString())
	),
	
	on create do
	(
		form = dotNetObject "MaxCustomControls.MaxForm"
		form.size = dotNetObject "System.Drawing.Size" size.x size.y
		form.Location = dotNetObject "System.Drawing.Point" pos.x pos.y
		form.StartPosition = form.StartPosition.Manual
		form.text = title
		dotnet.addEventHandler form "Shown" onShown
		dotnet.addEventHandler form "Move" onMove
	)
)
w = formHolder()
w.open()

I鈥檓 not looking for properties/functions of the sender. But I want to access properties or functions in the struct in which the handler is defined.
In your example, try to print pos or size in onShown, you鈥檒l get an exception.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

slight modification:


 struct formHolder 
 (
 	form,
 	size = [200,270],
 	pos = [900,150],
 	title = "The Form",
 	fn open = (if iskindof form dotnetobject do form.Showmodeless()),
 	fn close = (if iskindof form dotnetobject do form.Close()),
 	fn onShown s a = 
 	(
 		format "%
" (s.WindowState.toString())
 	),
 	fn onMove s a = 
 	(
 	    format "default:% %
" s.tag.value.pos (s.Location.toString())
 	),
 	
 	on create do
 	(
 		form = dotNetObject "MaxCustomControls.MaxForm"
 	    form.tag = dotnetmxsvalue this
 		form.size = dotNetObject "System.Drawing.Size" size.x size.y
 		form.Location = dotNetObject "System.Drawing.Point" pos.x pos.y
 		form.StartPosition = form.StartPosition.Manual
 		form.text = title
 		dotnet.addEventHandler form "Shown" onShown
 		dotnet.addEventHandler form "Move" onMove
 	)
 )
 w = formHolder()
 w.open()
 

Yep, I had thought of the Tag property too, to send the instance along with the sender.
However, not all .NET classes have a Tag property, only in the System.Windows.Forms namespace. The FileSystemWatcher for example doesn鈥檛鈥?/p>

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

i overrode FileSystemWatcher to add tag property

Yes alright, that is a solution. But to be honest, I don鈥檛 find it very pretty鈥?br>
You鈥檇 need a dll file just for that. So if there鈥檚 a better and more maintainable way, I鈥檇 be very interested.

1 Reply
(@denist)
Joined: 11 months ago

Posts: 0

as usually:


fn createFileSystemWatcher =
(
	source = ""
	source += "using System;
"
	source += "using System.IO;
"
	source += "namespace MXS
"
	source += "{
"
	source += "	public class FileWatcher: FileSystemWatcher { public Object Tag; }
"
	source += "}
"
	
	csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
	compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
--	compilerParams.CompilerOptions = "-unsafe"
	compilerParams.ReferencedAssemblies.Add("System.dll");

	compilerParams.GenerateInMemory = on
	compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
	compilerResults.CompiledAssembly.CreateInstance "MXS.FileWatcher"
)
global FileWatcherObject = createFileSystemWatcher()

Hm that鈥檚 interesting. Still not extremely portable and imo still a hack, but much better already.

Any idea why this behavior is occurring in the first place by the way?

2 Replies
(@denist)
Joined: 11 months ago

Posts: 0

why is it not portable and a hack? it鈥檚 the nature of .net . it鈥檚 the assembly as any other.

(@pjanssen)
Joined: 11 months ago

Posts: 0

It鈥檚 having to create a new class just to fix a problem that is totally unrelated to it. The problem isn鈥檛 with the FileSystemWatcher class, not even .NET, but with the maxscript wrapper for as far as I can see.
If this is the only way around it, then so be it, but you鈥檒l have to agree with me that it isn鈥檛 pretty

Thanks for your help.

unfortunately I can鈥檛 wait when max developers fix all bugs. Developing for Max has always been a hack for me. That is the nature of MAX

Haha that鈥檚 very true (unfortunately)

I filed this bug several months ago. If I am not wrong, it鈥檚 the same problem.

So what I did was this:

(
   	local MPEventHandler
   	struct MyPanel
   	(
   		fn EventHandler sender e = (),
   		
   		fn AddEventHandlers pState =
   			DotNet.AddEventHandler MyPanelForm "Activated" MPEventHandler
   	)
   	
   	local MP = MyPanel()
   	fn MPEventHandler sender e = MP.EventHandler sender e
   )

Let me know if this is the same problem. (:

Light

Lately, I鈥檝e taken to adding a instance to the global namespace with whenever I create a singleton-like struct. I make sure to use the 鈥?:鈥?prefix in the struct definition so that I always know I am referring to a global.

Lipstick on a pig.

struct formHolderDef 
(
	form,
	size = [200,270],
	pos = [900,150],
	title = "The Form",
	fn open = (if iskindof form dotnetobject do form.Showmodeless()),
	fn close = (if iskindof form dotnetobject do form.Close()),
		
	fn onShown s a = 
	(
		print (s.WindowState.toString())
	),
	
	fn onMove s a = 
	(
		print (s.Location.toString())
		print ::formHolder.size
		print ::formHolder.pos
	),
	
	fn init =  
	(
		form = dotNetObject "MaxCustomControls.MaxForm"
		form.size = dotNetObject "System.Drawing.Size" size.x size.y
		form.Location = dotNetObject "System.Drawing.Point" pos.x pos.y
		form.StartPosition = form.StartPosition.Manual
		form.text = title
	
		dotnet.addEventHandler form "Shown" onShown
		dotnet.addEventHandler form "Move" onMove
	),
	initialized = init()
)

::formHolder = formHolderDef()

::formHolder.open()

2 Replies
(@denist)
Joined: 11 months ago

Posts: 0

sometimes newly created structure doesn鈥檛 know its own global or local name.

(@pjanssen)
Joined: 11 months ago

Posts: 0

In fact, it never should. All it should know about is what happens inside itself
It should not look at its own properties or functions through a reference from outside.

Hmm yes if there鈥檚 one thing I鈥檇 like to avoid it鈥檚 creating globals that should not be used by anything except the script itself鈥?/p>

@light: looks like that鈥檚 the same issue indeed.

Page 1 / 2