[Closed] WPF in Max
I’ve started a blog where I posted a simple example of hosting something created with WPF inside of Max. Comments and questions welcomed.
Awesome, Thanks for taking the time to share your research on this James, I fear I may have a fair few questions in the future!
Hey guys, just to remember you I did some tests some time ago and seeing what you guys are doing nowadays I thought this example would be very cool to show:
XamlReader=dotnetclass "System.Windows.Markup.XamlReader"
XamlString="<Window
xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"
xmlns:x=\"http://schemas.microsoft.com/winfx/2006/xaml\"
Title=\"Window1\" Height=\"300\" Width=\"300\">
<Grid>
<Button Height=\"22\" HorizontalAlignment=\"Left\" Margin=\"12,12,0,0\" Name=\"Button1\" VerticalAlignment=\"Top\" Width=\"87\">Button</Button>
<ComboBox Margin=\"0,12,12,0\" Name=\"ComboBox1\" Height=\"22\" VerticalAlignment=\"Top\" HorizontalAlignment=\"Right\" Width=\"122\" />
<ListBox Margin=\"12,58,12,12\" Name=\"ListBox1\" />
</Grid>
</Window>"
XamlWindow=XamlReader.Parse XamlString
XamlWindow.Show()
This would be great for your Character Framework Pete!
Thanks for the info guys.
James – FYI it works for me in 2010 64bit on XP64. The visual style is different to your screenshot I believe due to being XP but I think you just need to have .NET 3.5 installed for it to work, at least for 2010. I seem to remember having a problem with someone’s WPF example in 2009 though.
Thanks for pointing that out. I was getting an error in 2010 for some reason, and I know that Autodesk updated the .Net version for 2011, which is why I thought it just wouldn’t work. But I’ll try looking into it some more and update the blog post.
Hey Kameleon. I didn’t know about XamlReader. Thanks for pointing that out. I’ll have to look into it some more. But my first concern would be that this wouldn’t be a good way to create a more robust tool. While there is a lot you can do with pure Xaml, at a certain point you may need to add more functionality in the code behind file, add extra classes, etc., especially when it comes to interacting with Max using the MaxscriptSDK functions that Lone Robot has talked about.
But thanks again for bringing it up. I love finding new tools to play with.
FIY, here’s another way to create a WPF form (without the ElementsHost control):
dnWindow=dotnetobject "System.Windows.Window"
dnWindow.Title="WPF Test"
dnWindow.Height=200
dnWindow.Width=200
dnColor=dotnetobject "System.Windows.Media.SolidColorBrush"
dnColor.Color=(dotnetclass "System.Windows.Media.Colors").AliceBlue
dnCanvas=dotnetobject "System.Windows.Controls.Canvas"
dnCanvas.Background=dnColor
dnButton=dotnetobject "System.Windows.Controls.Button"
dnButton.Height=23
dnButton.Width=100
dnButton.Content="WPF Button Test"
dnCanvas.SetTop dnButton 10
dnCanvas.SetLeft dnButton 10
dnWindow.Content=dnCanvas
dnCanvas.Children.Add(dnButton)
dnWindow.Show()
That works too. The nice thing about using a WPF window is that you can do some pretty cool things with it visually, like completely changing the shape and other nice effects.
The downside is that if you want it to act like it’s part of Max, you have to manage the owner and the windows background and foreground colors manually. But putting the control in a Rollout or MaxForm using ElementHost gets you those things for free. And a rollout even lets you dock it.
Just for fun, I tried the WPF window with my progress bar and works perfectly, with the caveats I’ve already mentioned.
dotNet.loadAssembly @"<folder name>\ProgressBar\ProgressBar\bin\Debug\ProgressBar.dll"
bar = dotNetObject "ProgressBar.UserControl1"
frm = dotnetobject "System.Windows.Window"
frm.title = "Progress"
frm.width = bar.width + 16
frm.height = bar.height + 34
frm.windowStartupLocation = frm.windowStartupLocation.centerScreen
frm.windowStyle = frm.windowStyle.toolWindow
frm.content = bar
frm.show()
-- set number of steps to use
bar.steps = 50
-- loop through the steps
for i = 1 to bar.steps do
(
-- force the UI to update
(dotNetClass "System.Windows.Forms.Application").DoEvents()
-- increment one step and change label
bar.DoStep()
bar.ProgressLabel = "Thing " + i as string
sleep .05
)
frm.close()
Very cool guys. I need all the time in the world to keep up on all this stuff.
I don’t see those issues as big ones. So write a dotNetLib that takes care of all those sorts of things when ever you use them.
Interesting to note that this will work in a rollout? Will it work in a rollout in the modifier panel and still allow event handlers or is that still out of scope?
Yep, definitely not a blocking issue, but something to be aware of.
Here is what the rollout version would look like…
-- load the progress bar library
dotNet.loadAssembly @"<folder location>\ProgressBar\ProgressBar\bin\Debug\ProgressBar.dll"
-- load the WPF Integration library needed to create the ElementHost control
dotNet.loadAssembly @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\WindowsFormsIntegration.dll"
bar = dotNetObject "ProgressBar.UserControl1"
size = [bar.width,bar.height]
frm = rollout progressBar_RLT "Progress" width:size.x height:size.y
(
dotNetControl eh "Integration.ElementHost" width:size.x height:size.y align:#left offset:[-14,-5]
on progressBar_RLT open do
(
eh.child = bar
)
)
createDialog progressBar_RLT
-- set number of steps to use
bar.steps = 50
-- loop through the steps
for i = 1 to bar.steps do
(
-- force the UI to update
(dotNetClass "System.Windows.Forms.Application").DoEvents()
-- increment one step and change label
bar.DoStep()
bar.ProgressLabel = "Thing " + i as string
sleep .05
)
destroyDialog progressBar_RLT
The only thing different is the creation of the rollout and then putting the controls inside of it. Note, I just figured out the you don’t really need the UserControl. Just put the ElementHost inside the rollout or window, and then the WPF control inside of that. I had the UserControl because I had originally created a generic “WPF host” control in C# which I was bringing into Max. But if you’re building it in Max to begin with, you don’t need it.
As far whether it would work in a modifier panel, I don’t know. It would just be another control in the rollout, so I’m assuming it would work the same as using it in a regular non-modifier rollout.
Currently the issue with using dotNet controls in the modifier panel is with the scope of the event handlers. You are forced to write the events the same as you do for other Max UI items. Trying to add event handlers using dotNet.addEventHandlers does not work. I would assume the same issue is going to apply with WPF.
Creating your tool with Visual Studio and compiling a dll that you would then load into the modifier should remove this limitation. Of course, relying on compiled components has it’s own drawbacks.
Yes it would as you could then just use the standard event handlers in Max script. A bit of a pain for anything simple. Thanks for the suggestion though.
Windows Presentation foundation. It is replacing GDI+, a quick google will get you way more information then can be posted here.