.

.NET WPF and Maxscript.

Coding exploration.

ScriptImg

Quels Maxscipteurs n’a jamais maudits ce langage ?

Ne pas pouvoir séparer le code “d’action” du code d’interface, de pouvoir faire une interface un peu dynamique sans s’arracher les cheveux.
Avec l’arrivée du .NET, les choses se sont améliorées…si on arrive à passer les premières barrières d’incompréhensions (surtout si comme moi, vous n’êtes pas un codeur “Natif” mais un graphiste qui a glissé vers le code). Puis l’implantation du WPF m’a mis des étoiles pleins les yeux. Je sentais des possibilités énormes et à force de recherche et pas mal d’acharnement, j’ai réussi à mettre en place un code que je trouve intéressant. C’est celui-ci que je vais vous présenter.

Le principe ? Toute la définition graphique codée dans un fichier XAML, on load ce fichier dans le maxscript, et on crée les “Events”, nos fonctions etc…

L’avantage, on soulage le code, c’est plus facile de faire des mises à jour purement graphique et surtout on bénéficie du code xaml (plus souple et graphiquement des milliards de fois plus puissant que le maxscript)
En gros on peut à peu près tout faire, du bouton ronds et jolie, à des animation 2D voir 3D, créer des formes vectoriels, avoir des Layouts d’interface pour placer ses buttons et autres exactement où l’on veut, Bref des possibilités énormes et ce n’est que la face cachée de l’iceberg.

Nous allons avoir besoin d’un logiciel, http://www.kaxaml.com/ c’est un éditeur de fichier xaml gratuit, simple, portable et efficace.

Kaxaml

Nous allons donc créer notre premier fichier xaml, installer Kaxaml, ouvrez le et c’est parti :

On supprime tout ce qui est affiché dans la fenêtre et on tape :
[xml]
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Name="Button01" Width="80" Height="25">Button01</Button>
</UserControl>
[/xml]
Dans la première balise, on définit notre control, ici un “Usercontrol”, pourquoi cela ? Et bien comme ça mon code marche en maxscript à la fois dans un “Rollout” et dans un WindowsForm.
Les deux lignes suivantes sont des namespaces à charger obligatoirement.
Wahooo ! Oui je sais, c’est trop beau , mais il faut bien commencer par du classique et encore je vous épargne le “Hello World !”.

On sauve notre Xaml dans un petit dossier bien ranger bien propre et on passe sous Max !
Et là je ne vous apprends rien, Menu > Maxscript > Nouveau script :

On load une library .Net pour accéder au dotNetControl “Integration.ElementHost” qui va nous servir à loader un fichier extérieur :
[php]
— load library
dotNet.loadAssembly @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.0\WindowsFormsIntegration.dll"
[/php]

Ici on configure le path du Xaml et le nom du fichier :
[php]
— Get Relative Path of this script
RelativePath = "C:Votredossier\votresousDossier\"
— Get Xaml File
xamlfile = "test00.xaml"
[/php]

Bon maintenant on crée un Rollout, rien de bien compliqué, et comme Control Visuel on intègre notre “Integration.ElementHost” tiré de la librairie chargé plus haut :
[php]
— create Rollout
try (destroyDialog BlackBeard_XamlUI) catch()
rollout BlackBeard_XamlUI "BlackBeard Xaml UI"
(
dotNetControl XamlControl "Integration.ElementHost" align:#left offset:[-13,-5]
[/php]

Rien de bien exceptionnelle, je donne une taille au rollout et a “XamlControl “. Je definis le path complet du fichier xaml :
[php]
— Init
on BlackBeard_XamlUI open do
(
rolloutSize = [375,626]
BlackBeard_XamlUI.width = XamlControl.width = rolloutSize .x
BlackBeard_XamlUI.height = XamlControl.height = rolloutSize .y
— Get Xaml File
xamlfilepath = RelativePath+"\\"+xamlfile
[/php]

On attaque la partie intéressante. On va créer un dotNetObject “IO.FileStream” pour streamer le fichier xaml. Puis le lire avec la dotNetClass “Windows.Markup.XamlReader” et libérer le stream de la mémoire :
[php]
— Configure FileStream
dotNetFileMode = (dotNetClass "IO.FileMode").Open — Mode de creation
dotNetFileAcces = (dotNetClass "IO.FileAccess").Read — Mode de lecture
— Create Stream
dotNetFileStream = dotNetObject "IO.FileStream" xamlfilepath dotNetFileMode dotNetFileAcces
— Read Xaml and Close Stream
XamlReader = (dotNetClass "Windows.Markup.XamlReader").Load dotNetFileStream
dotNetFileStream.close
[/php]

On ajoute notre XamlReader au control du rollout :
[php]
— Add Xaml to ElementHost "XamlControl"
XamlControl.child = XamlReader
/* New to Max 2010, we use this to make sure Maxscript Garbage collection
does not destory our Functions and events before we are done with them */
dotNet.setLifetimeControl XamlReader #dotnet
[/php]

On va enfin rechercher le button et lui appliquer un event.
[php]
— Init variable Controls
theControl = XamlControl.Child
theButton = theCanvas.FindName "Button01"
— Create Event for the button
fn createPoint sender eventargs = (
Point()
)
— Search the control and add Event
dotNet.addEventHandler theButton "Click" createPoint
)
)
createDialog BlackBeard_XamlUI
[/php]
Tadam ! Génial j’ai un button qui crée un point !

xamlButton01

Oui, mais en Xaml j’ai dit que l’on avait des feuilles de style (: du coup avec ce xaml là les choses deviennent intéressantes :
[xml]
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<ResourceDictionary>
<Style x:Key ="BtnPlayTemplate" TargetType ="{x:Type Button}">
<Setter Property ="Foreground" Value ="Black"/>
<Setter Property ="FontWeight" Value ="Bold"/>
<Setter Property ="Template">
<Setter.Value>
<ControlTemplate TargetType ="{x:Type Button}">
<Viewbox x:Name="LayoutRoot" Stretch="Fill">
<Grid>
<Ellipse Name ="ShadowRing" Fill="Black" Stretch="Fill">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset="1" Color="#00000000"/>
<GradientStop Offset="0.9" Color="#00000000"/>
<GradientStop Offset="0.7" Color="Black"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Name ="OuterRing" Fill="Green" StrokeThickness="1.5" Stroke="White" Margin="3,3,3,3" Stretch="Fill"/>
<Ellipse Name ="ShadowRing2" Fill="Black" Stretch="Fill" Margin="4.5" Opacity="0.4">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Offset="1" Color="Black"/>
<GradientStop Offset="0.7" Color="#00000000"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Polygon Points="0,0 0,10 10,5" StrokeThickness="1.2" Stroke="White" Margin="12,9,10,9" Stretch="Fill" Opacity="0.6">
<Polygon.Fill>
<SolidColorBrush Color="White" Opacity="0.4"/>
</Polygon.Fill>
</Polygon>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Viewbox>
<ControlTemplate.Triggers>
<Trigger Property ="IsMouseOver" Value ="True">
<Setter TargetName ="OuterRing" Property ="Fill" Value ="#FFFF1919"/>
</Trigger>
<Trigger Property ="IsPressed" Value ="True">
<Setter TargetName ="OuterRing" Property ="Fill" Value ="#FFFF5454"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
</UserControl.Resources>

<Grid>
<Button Name="Button01" Style="{StaticResource BtnPlayTemplate}" Width="80" Height="80"/>
</Grid>
</UserControl>
[/xml]

xamlButton02

Les sources à télécharger : XamlTuto
Et pour les plus courageux, je vous mets un lien vers un site très bien fait qui parle de xaml : http://wpftutorial.net

J’espère que ce Tutorial vous aura été utile, je ferais peut-être une suite avec plus de travail sur l’interface qu’un simple bouton.

SeeYa