Notifications
Clear all

[Closed] XtraTreeList getValue

 PEN

Mike if you find the time could you give us a break down on what that C# code is doing and where the problem is that it is correcting. I have an idea but want to make sure that I’m clear on it.

Hi Paul, here’s my take on it. Looks like the problem is with maxscript. the GetValue method of the TreeListNode returns a System.Object, which obviously doesn’t exist in maxscript so it’s being incorrectly cast to an integer. Mike’s code simply casts the Object to a float (Single) before returning, which maxscript can handle correctly. He also added a bunch of error checking. Please correct me if I’m wrong / missed anything Mike.

EDIT: i just realised after posting that it still doesn’t quite make sense since the you can use GetValue correctly until you enter a value…

1 Reply
(@biddle)
Joined: 1 year ago

Posts: 0

Yup, that what’s happening.

Maxscript mishandles the conversion from a .NET Object to a float so my snippet removes any ambiguity. I chose to use reflection and do a method invoke on a function called “get_Item” so that (hopefully!) it will work for any derived object that exposes an Item[x] property (not just XtraTreeListNodes).

I’m not 100% sure why modifying the value causes MXS to change the way it interprets the Object.

If you change the logging printout to

format “Value: % is a % DText: % FValue: %
” val (classof val) dtxt fval

Then immediately after initialization you get :
Value: 0.5 is a Float DText: 0.5 FValue: 0.5

But then after a spinner update it’s:
Value: 1 is a Integer DText: 0.6 FValue: 0.6

It’s odd.

In my spare time I’ve been trying to tweak the mxsdotnet.dll so that it doesn’t need quite as much hand holding …it’s a long term labour of love. My thinking is that if you know what the type is that you want, you provide it as a named argument.

Instead of typing:

x = foo.get_value()

and hoping for the best, you could explicitly state:

x = foo.get_value returntype:float

 PEN

Well that is what I’m confused about. You can get the value until the repository item is changed.

Now here is the next problem, I can’t get the value as it is changing. What I’m getting is the last value. So as long as the repository spinner is active the cell isn’t getting the value updated. Only once I’m out of the edit mode do I see the correct value. Does this mean that we need to try and pull the value from the repository spinner instead, I don’t see a way yet to do that.

Edit: I should note as well that the CellValueChanging event is being called but the value isn’t not updating.

 PEN

I keep getting memory errors Mike. I will see if I can lock it down and I will pass on the message that it is reporting to me.

Here is an update.

Changes:

I made the 2nd arg of GetFloatItem an Object (was an Int32) to so you can pass an XtraTreeListNodeColumn (and not have to dereference that column’s .AbsoluteIndex). This made it simpler to call when handling a CellValueChanging(ed) event.

Added a GetFloatValue helper that will extract the “Value” property of an Object as a float.

if gItemHelperAssembly == undefined then
(
	global gItemHelperAssembly
)

-- Build up a snippet of code that will access the "Item[x]" pseudo-property of a dotNet object and return the value as a float.
fn newItemHelpers forceRecompile:false =
(
	if (forceRecompile or 
		(classof gItemHelperAssembly) != dotNetObject or 
		((gItemHelperAssembly.GetType()).ToString()) != "System.Reflection.Assembly") do
	(
		sb =  "using System;
"
		sb += "using System.Text;
"
		sb += "using System.Collections;
"
		sb += "using System.Reflection;
"
		
		sb += "class ItemHelpers
"
		
		sb += "{
"		
		sb += "  public Single GetFloatItem(Object tln, Object colId)
"
		sb += "  {
"				
		sb += "    Single ret = Single.MinValue;
"
		sb += "    Object retObj;
"
		
		sb += "    try {
"
		
		sb += "      Type tlnType = tln.GetType();
"
		sb += "      MethodInfo mi = tlnType.GetMethod(\"get_Item\");
"		

		sb += "      Object[] parms = new Object[1];
"
		sb += "      parms[0] = colId;
"	
	
		sb += "      retObj =  mi.Invoke(tln,parms);
"
		
		sb += "    }
"
		
		sb += "    catch {
"
		sb += "      throw new System.Exception(\"GetFloatItem Error: Failed to invoke \\\"get_Item()\\\" method on input object\");
"
		sb += "    }
"
		
		sb += "    try {
"
		sb += "      ret = Convert.ToSingle(retObj);
"
		sb += "    }
"
		
		sb += "    catch {
"
		sb += "      StringBuilder err = new StringBuilder();
"
		sb +=  "     err.AppendFormat(\"GetFloatItem Error: Value in column {0} will not convert to a float!  Value: {1} Type: {2}\", colId, retObj, retObj.GetType() ); 
"
		sb += "      throw new System.Exception(err.ToString());
"
		sb += "    }
"
		
		sb += "    return ret;
"
		
		sb += "  }
"
			
		sb += "  public Single GetFloatValue(Object tln)
"
		sb += "  {
"				
		sb += "    Single ret = 0;
"
		sb += "    Object retObj;
"
		
		sb += "    try {
"
		
		sb += "      Type tlnType = tln.GetType();
"
		sb += "      MethodInfo mi = tlnType.GetMethod(\"get_Value\");
"		

		sb += "      Object[] parms = new Object[0];
"
		
		sb += "      retObj =  mi.Invoke(tln,parms);
"
		
		sb += "    }
"
		
		sb += "    catch {
"
		sb += "      throw new System.Exception(\"GetFloatValue Error: Failed to invoke \\\"get_Value()\\\" method on input object\");
"
		sb += "    }
"
		
		sb += "    try {
"
		sb += "      ret = Convert.ToSingle(retObj);
"
		sb += "    }
"
		
		sb += "    catch {
"
		sb += "      StringBuilder err = new StringBuilder();
"
		sb +=  "     err.AppendFormat(\"GetFloatValue Error: Value will not convert to a float!  Value: {1} Type: {2}\", retObj, retObj.GetType() ); 
"
		sb += "      throw new System.Exception(err.ToString());
"
		sb += "    }
"
		
		sb += "    return ret;
"
		
		sb += "  }
"
		sb += "}
"

		csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
		compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
		
		-- Need to add referenced assemblies that the code snippet is 'using'
		compilerParams.ReferencedAssemblies.Add("System.dll");
		
		compilerParams.GenerateInMemory = true
		compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(sb)
		
		if (compilerResults.Errors.Count > 0 ) then
		(
			errs = stringstream ""
			for i = 0 to (compilerResults.Errors.Count-1) do
			(
				err = compilerResults.Errors.Item[i]
				format "Error:% Line:% Column:% %
" err.ErrorNumber err.Line \                                              
													 err.Column err.ErrorText to:errs 
			)
			MessageBox (errs as string) title: "Errors encountered while compiling C# code"
			format "%
" errs
			gItemHelperAssembly = undefined
			return undefined
		)
		else
		(
			gItemHelperAssembly = compilerResults.CompiledAssembly
		)
	)
	gItemHelperAssembly.CreateInstance "ItemHelpers"
)

   try(destroyDialog testR)catch()
   rollout testR "Test" 
   (
   	dotNetControl xtl "DevExpress.xtraTreeList.treeList" height:200
   	
	local ItemHelpers
	   
   	fn initXtl xtl=
   	(
		ItemHelpers = newItemHelpers() --forceRecompile:true
		
		xtl.OptionsSelection.MultiSelect = True
   		xtl.OptionsView.ShowRoot =true
   		xtl.OptionsView.ShowIndicator = false
   		xtl.OptionsView.AutoWidth = true
   		
   		col=xtl.columns.add()
   		col.visible=true
   		col.width=120
   		col.caption="Items"
   		xtl.columns.item[0].fixed = xtl.columns.item[0].fixed.left
   		
   		local xTraSpinner=dotNetObject "DevExpress.XtraEditors.Repository.RepositoryItemSpinEdit"
   		xTraSpinner.SpinStyle=xTraSpinner.SpinStyle.vertical
   		xTraSpinner.minValue=0.0
   		xTraSpinner.maxValue=1.0
   		xTraSpinner.Increment=.1
   		xTraSpinner.UseCtrlIncrement=true
   		xTraSpinner.isFloatValue=true
   		xTraSpinner.AllowNullInput=xTraSpinner.AllowNullInput.false
   		xTraSpinner.nulltext="---  "
   		xtl.RepositoryItems.add xTraSpinner
   
   		col=xtl.columns.add()
   		col.visible=true
   		col.caption="Val:"
   		col.columnEdit=xTraSpinner
   		col.UnboundType=col.UnboundType.Decimal
   	)
   	
   	fn addTargetNamesToEtl xtl theNodes:#("Test1","Test2","Test3")=
   	(
   		xtl.ClearNodes()
   		for i = 1 to theNodes.count do
   		(
   			n0=xtl.appendNode #(theNodes[i],0.5) -1
   				pos=xtl.appendNode #("Sub 1:",0.0) n0
   				rot=xtl.appendNode #("Sub 2:",0.0) n0
   		)
   	)
   
   	on xtl SelectionChanged senderArg arg do
   	(
   --			  formatProps senderArg
   		for i = 0 to senderArg.selection.count-1 do
   		(
			valItm = senderArg.selection.item[i].getValue 1
			txtItm = senderArg.selection.item[i].GetDisplayText 1
			fltItm = ItemHelpers.GetFloatItem senderArg.selection.item[i] 1
   			format "SelectionChanged: Index: % Value: % is a % Display Text: % Float Value: %
" i valItm (classof valItm) txtItm fltItm
   		)
   		
   	)
   
   	on xtl CellValueChanging senderArg arg do
   	(
		format "CellValueChangING: NodeId % Col % - " arg.node.id arg.column.AbsoluteIndex
		currVal = ItemHelpers.GetFloatItem arg.node arg.column
		newVal = ItemHelpers.GetFloatValue arg
		format "currval: % newval: %
" currVal newVal
   	)
   		
   	on xtl CellValueChanged senderArg arg do
   	(
		format "CellValueChangED: NodeId % Col % - " arg.node.id arg.column.AbsoluteIndex
		currVal = ItemHelpers.GetFloatItem arg.node arg.column
		newVal = ItemHelpers.GetFloatValue arg
		format "currval: % newval: %
" currVal newVal
   	)
   		
	on testR open do
   	(
   		initXtl xtl
   		addTargetNamesToEtl xtl
   	)
   )
   createDialog testR width:300 height:220
   

Check this thread, where I had the same issue with NumericUpDown controls. There are a couple more solutions in there (the simplest being instead of getting the .value get “<control>.text as float”)…

http://forums.cgsociety.org/showthread.php?f=98&t=763277&highlight=updown

2 Replies
(@denist)
Joined: 1 year ago

Posts: 0

“.text as float” is not a solution because I can (or want to) use special Display Format for any “float” cell.

I’m fighting with this problem almost a day and could find any other then c# solution. !!!KCUF

This is a MXS issue, not a .NET …

(@jhaywood)
Joined: 1 year ago

Posts: 0

Yeah, I didn’t say it was the best, just the simplest to implement, especially for a non-programmer like myself.

“decimal == integer” <sigh>

I was thinking about using the getProperty asDotNetObject:true and convert trick, but I don’t think you can use it for array-like properties (like Item[]) as you need to pass the array index as a parameter.

It’s probably the best way to get the .value property – but I already had all that C# in there for arrays and I couldn’t resist extending it =)

Why bother with the keys when the Jaws Of Life are available?

 PEN

Mike you saved my a$$. Thanks a million and if there is anything that I can do for you, please just ask.

I tried do to same thing on MXS as biddle did using c#

node = <TreeListNode>
t = node.getType()
s = t.getmethod “get_Item”
v = s.Invoke node #(1)
– result is still “integer”

ea = (dotnetclass “System.Reflection.BindingFlags”).ExactBinding
db = (dotnetobject “System.DefaultBinder”) – ??? how to set in to “convert to Single”
ci = (dotnetclass “System.Globalization.CultureInfo”).CurrentCulture

v = s.Invoke node ea db #(1) ci
– result is still “integer”

in c# [color=silver]<DevExpress.XtraTreeList.Nodes.[size=2]TreeListNode>.GetValue() returns an Object of cause…
[/size][/color]

1 Reply
(@biddle)
Joined: 1 year ago

Posts: 0

I think it would have worked if you could specify that you want the dotnetobject returned from the call to invoke().

Something like:
v = s.Invoke node #(1) asdotnetObject:true

Then you’d be free to convert the decimal .NET object to the float you need.

But if you can do that, you could remove all the method lookup cruft and just call:

v = node.get_item 1 asdotnetObject:true

In the end, I’m not sure why the asdotnetObject keyword option is limited to the getProperty call. Would dearly love to have something like it for .NET methods too.

 PEN

Well Mike I think that i would have ended up in the same boat. I would not have been getting the real time value. And you right, you can’t use getProperty as there is no property name to pass. I tried shoe horning that in there and it didn’t work at all. What you have created now is working real time in the modifier panel.

I will try and find the time after this project to document all of this on my site.

Page 2 / 3