Docked .Net controller redraw issue

Become a member of the CGSociety

Connect, Share, and Learn with our Large Growing CG Art Community. It's Free!

THREAD CLOSED
 
Thread Tools Search this Thread Display Modes
Old 03 March 2012   #1
Docked .Net controller redraw issue

Hi!
I got a problem with a docked custom .net control not being redrawn when I do operations like opening the material editor, converting objects to editable poly, opening the curve editor etc. It looks like the whole max UI is updating itself when I do operations like that. If I undock the rollout with the controller, it redraws itself normally when doing the aforementioned operations. Is there a way to remedy this issue?

Håvard
__________________
Homepage clicky clickey!
 
Old 03 March 2012   #2
what control are talking about?
it's known problem... there are some solutions but they are different for different controls.
if you post a snippet it will help.
 
Old 03 March 2012   #3
usually a timer to force the redraw works for command panel redraw issues. the timer calls the redraw/invalidate method on the control itself. hackilicious!


rollout Trackbot "" width:170 height:249
(
dotNetControl TBbtn1 "button" pos:[1,3] width:156 height:54
dotNetControl TBbtn2 "button" pos:[1,61] width:156 height:54
dotNetControl TBbtn3 "button" pos:[1,119] width:156 height:54
dotNetControl TBbtn4 "button" pos:[1,174] width:156 height:54
timer refresh "" interval:1
on Trackbot open do refresh.active = true

on refresh tick do
	(	
	for i in Trackbot.controls where classof i == dotNetControl do i.refresh()
	refresh.active = false
	)
)
createdialog trackbot
__________________
Regards,
Pete

Read my technical blog - lonerobot.net
 
Old 03 March 2012   #4
The control inherits usercontrol, and it has multiple other controls that inherits usercontrol, treeview etc. It is written in c#, and the control is in a rollout which is in a docked rolloutfloater. I don't know what code I can show that would help.

But since I have access to the MaxNotificationListener I thought I could use that, but I need the right system notification code and I dont know which one:
http://download.autodesk.com/global...tion_codes.html

Using a timer to redraw would have to be my last option though, but I would be cool to find a more subtle approach
__________________
Homepage clicky clickey!
 
Old 03 March 2012   #5
Originally Posted by haavard: The control inherits usercontrol, and it has multiple other controls that inherits usercontrol, treeview etc. It is written in c#, and the control is in a rollout which is in a docked rolloutfloater. I don't know what code I can show that would help.

does it mean that only written by you controls don't redraw? i don't think so. make a simple rolloutfloater with couple .net controls, which being docked doesn't redraw its controls.
 
Old 03 March 2012   #6
That right, like this snippet shows, controls under other controls don't redraw themselves after certain operations in max. Run this code and open the material editor or convert an object to editable mesh/poly. The button is not redrawn.
(
	height = (filterString (getINIsetting (cui.getConfigFile()) "Command Panel" "FRect") " ")[3] as integer
	::rf = newRolloutFloater "rf" 250 height
		
	rollout rol "rol"
	(
		dotnetcontrol treeview "system.windows.forms.treeview" width:220 height:(height - 100)
		dotnetcontrol panel "system.windows.forms.panel" width:220 height:50
		on rol open do
		(
			b = dotnetobject "system.windows.forms.button"
			panel.controls.add b
			--b.dock = (dotnetclass "system.windows.forms.dockstyle").fill
		)
	)		
	addRollout rol rf 
	cui.registerDialogBar rf style:#(#cui_dock_all, #cui_floatable, #cui_handles, #cui_dock_horz, #cui_max_sized)	
	cui.dockDialogBar rf #cui_dock_left
)

I don't know if this is a general case or just on my machine
__________________
Homepage clicky clickey!
 
Old 03 March 2012   #7
I haven't tried your example code yet, but this issue reminds me of reports I got from several Outliner users. They reported that the treeview occasionally stopped redrawing. I never found a solution for it, since I expected it to be an error in my implementation, not a fault with max.
But this might change that idea, so I'll follow this closely
 
Old 03 March 2012   #8
Originally Posted by haavard: That right, like this snippet shows, controls under other controls don't redraw themselves after certain operations in max. Run this code and open the material editor or convert an object to editable mesh/poly. The button is not redrawn.
I don't know if this is a general case or just on my machine


i confirm the issue. the controls don't redraw in max 2012, and redraw in max 2010.
both my maxs are in Direct3D 9.0 mode. So it's probably not a driver issue.
 
Old 03 March 2012   #9
and the rollout might not be docked. just enough to registerDialogBar... the controls stop redrawing.
 
Old 03 March 2012   #10
here is a solution with using of the NativeWindow to catch WM_PAINT message and send WindowRedraw to handled window:

fn CreateWindowOps =
(

source = ""
source += "using System;\n"
source += "using System.Windows.Forms;\n"
source += "using System.Runtime.InteropServices;\n"
source += "namespace WindowOps\n"
source += "{\n"
source += "	public class MessageEventArgs : EventArgs\n"
source += "	{\n"
source += "		public MessageEventArgs(Message message) { this.message = message; }\n"
source += "		public Message message;\n"
source += "	}\n"
source += "	public class WindowHooker : NativeWindow\n"
source += "	{\n"
source += "		private const int WM_PAINT = 0x0F;\n"
source += "		public WindowHooker() { }\n"
source += "		public event EventHandler MessageReceived;\n"
source += "		protected override void WndProc(ref Message m)\n"
source += "		{\n"
source += "			switch (m.Msg)\n"
source += "			{\n"
source += "				case WM_PAINT:\n"
source += "					MessageReceived(this, new MessageEventArgs(m));\n"
source += "					break;\n"
source += "				default:\n"
source += "					break;\n"
source += "			}\n"
source += "			base.WndProc(ref m);\n"
source += "		}\n"
source += "	}\n"
source += "}\n"

	csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
	compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"

	compilerParams.ReferencedAssemblies.AddRange #("System.dll", "System.Windows.Forms.dll")

	compilerParams.GenerateInMemory = true
	compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
		
	compilerResults.CompiledAssembly
)
global WindowOps = CreateWindowOps()

(
	try
	(
		cui.unregisterDialogBar DialogBar
		closeRolloutFloater DialogBar
	)
	catch()
	
	global DialogBar = newRolloutFloater "rf#" 250 300
		
	rollout redrawRol "Redraw Test"
	(
		local hook 
		dotnetcontrol lv "ListView" width:220 height:100
		dotnetcontrol pn "UserControl" width:220 height:24
		
		on redrawRol open do
		(
			lv.view = lv.view.Details
			lv.Columns.add "Name" 100
			lv.Columns.add "ID" 100
			
			bt = dotnetobject "Button"
			bt.text = "Button"
			bt.Dock = bt.Dock.Left
			
			lb = dotnetobject "Label"
			lb.text = "Label"
			lb.Dock = lb.Dock.Right
			
			pn.controls.addrange #(lb,bt)

			hook = WindowOps.createInstance "WindowOps.WindowHooker"
			hook.AssignHandle (dotnetobject "IntPtr" (windows.getchildhwnd 0 "rf#")[1])
			
			fn onMessageReceived s e =
			(
				RDW_INVALIDATE	= 0x0001
				RDW_ALLCHILDREN	= 0x0080
				
				format "hook: % %\n" (formattedPrint e.message.hwnd format:"#x") (formattedPrint e.message.msg format:"#x")
				user32.redrawallwindow s.handle (RDW_INVALIDATE	+ RDW_ALLCHILDREN)
			)
			dotnet.addEventHandler hook "MessageReceived" onMessageReceived
		)
		on redrawRol close do
		(
			hook.ReleaseHandle()
		)
	)		
	addRollout redrawRol DialogBar
	cui.registerDialogBar DialogBar style:#(#cui_dock_all, #cui_floatable, #cui_handles, #cui_dock_horz, #cui_max_sized)	
)


if you comment hook's event handler you will see that the controls will stop redrawing.
Dialog itself receives PAINT message but for some reason doesn't notify its .net children.
i'm forcing redraw sending INVALIDATE message to window and all it's children.

you can send the redraw message without Event System, by doing it from WndProc.
 
Old 03 March 2012   #11
oops... i didn't give user32.redrawallwindow function.
it's from my library. i forgot that it's not integrated into MAX yet.
to late for today but i will fix it tomorrow.
 
Old 03 March 2012   #12
Wow, thanks! This is perfect.

I used this

public static class User32
{
    [DllImport("user32.dll")]
    static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, uint flags);
    public static bool RedrawAllWindow(IntPtr hWnd, uint flags) 
    { 
        return RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, flags); 
    }
}
__________________
Homepage clicky clickey!
 
Old 03 March 2012   #13
Originally Posted by haavard: Wow, thanks! This is perfect.

I used this

  public static class User32
  {
      [DllImport("user32.dll")]
      static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, uint flags);
      public static bool RedrawAllWindow(IntPtr hWnd, uint flags) 
      { 
          return RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, flags); 
      }
  }
  

absolutely right... i'm doing the same.

so because you are using your own controls it shouldn't be a big deal to add to your list one more - pain-hook native window

Last edited by denisT : 03 March 2012 at 12:31 AM.
 
Old 03 March 2012   #14
Very nice!
__________________
Regards,
Pete

Read my technical blog - lonerobot.net
 
Old 03 March 2012   #15
I knew that I was overdoing something...
After a little thinking I guessed that MAX creates dotnetcontrols with some wrong window style flag. And I was right with this idea. MAX sets the WS_CLIPCHILDREN flag supposing that dotnetcontrol can't be a parent. Setting this flag also blocks the redrawing of combined controls like ListView(body and header), NumericUpDown(buttons and textbox), etc.

So the good solution is more simple than using of NativeWindow. The thing that we need is only remove the WS_CLIPCHILDREN flag:

fn CreateWindowLongAssembly =
(
	source = "using System;\n"
	source += "using System.Runtime.InteropServices;\n"
	source += "class WindowLong\n"
	source += "{\n"
	source += "		[DllImport(\"user32.dll\", EntryPoint=\"GetWindowLong\")]\n"
	source += "		public static extern Int32 GetWindowLong(IntPtr hWnd, Int32 index);\n"
	source += "		[DllImport(\"user32.dll\", EntryPoint=\"SetWindowLong\")]\n"
	source += "		public static extern Int32 SetWindowLong(IntPtr hWnd, Int32 index, Int32 newVal);\n"
	source += "}\n"

	csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
	compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"

	compilerParams.GenerateInMemory = on
	compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
	
	assembly = compilerResults.CompiledAssembly
	assembly.CreateInstance "WindowLong"
)
global WindowLong = CreateWindowLongAssembly()

mapped fn removeCLIPCHILDREN control =
(
	GWL_STYLE = -16
	WS_CLIPCHILDREN = 0x02000000L 

	hwnd = control.get_handle asdotnetobject:on
	flags = bit.xor (WindowLong.GetWindowLong hwnd GWL_STYLE) WS_CLIPCHILDREN
	WindowLong.SetWindowLong hwnd GWL_STYLE flags
)


(
	try
	(
		cui.unregisterDialogBar DialogBar
		closeRolloutFloater DialogBar
	)
	catch()
	
	global DialogBar = newRolloutFloater "rf#" 250 300
		
	rollout redrawRol "Redraw Test"
	(
		dotnetcontrol lv "ListView" width:220 height:100
		dotnetcontrol pn "UserControl" width:220 height:24
		
		on redrawRol open do
		(
			lv.view = lv.view.Details
			lv.Columns.add "Name" 100
			lv.Columns.add "ID" 100
			
			bt = dotnetobject "Button"
			bt.text = "Button"
			bt.Dock = bt.Dock.Left
			
			lb = dotnetobject "Label"
			lb.text = "Label"
			lb.Dock = lb.Dock.Right
			
			pn.controls.addrange #(lb,bt)
			
			removeCLIPCHILDREN #(lv,pn)
		)
	)		
	addRollout redrawRol DialogBar
	cui.registerDialogBar DialogBar style:#(#cui_dock_all, #cui_floatable, #cui_handles, #cui_dock_horz, #cui_max_sized)	
)


Enjoy!
 
Thread Closed share thread



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
CGSociety
Society of Digital Artists
www.cgsociety.org

Powered by vBulletin
Copyright ©2000 - 2006,
Jelsoft Enterprises Ltd.
Minimize Ads
Forum Jump
Miscellaneous

All times are GMT. The time now is 12:04 PM.


Powered by vBulletin
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.