<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Tristan Root&#039;s Blog</title>
	<atom:link href="http://triroot.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://triroot.wordpress.com</link>
	<description></description>
	<lastBuildDate>Thu, 18 Feb 2010 03:19:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='triroot.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/fcf007193b9d99d154cbbe62ae8bca7a?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Tristan Root&#039;s Blog</title>
		<link>http://triroot.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://triroot.wordpress.com/osd.xml" title="Tristan Root&#039;s Blog" />
	<atom:link rel='hub' href='http://triroot.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Wpf MVVM 3D Model Viewer &#8211; More View Panels</title>
		<link>http://triroot.wordpress.com/2010/02/18/wpf-mvvm-3d-model-viewer-more-view-panels/</link>
		<comments>http://triroot.wordpress.com/2010/02/18/wpf-mvvm-3d-model-viewer-more-view-panels/#comments</comments>
		<pubDate>Thu, 18 Feb 2010 03:19:09 +0000</pubDate>
		<dc:creator>triroot</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[3D Model Viewer]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[mvvm]]></category>

		<guid isPermaLink="false">http://triroot.wordpress.com/?p=61</guid>
		<description><![CDATA[Introduction In a previous post I showed you how to create a basic 3D model viewer in WPF using the MVVM pattern. In this post I&#8217;m going to show you how to take advantage of the MVVM design of this application by adding a couple more views (one view to move the camera, and one [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=triroot.wordpress.com&amp;blog=10727597&amp;post=61&amp;subd=triroot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div style="font-family:Calibri;font-size:11pt;">
<h3>Introduction</h3>
<p>In a <a href="http://triroot.wordpress.com/2009/12/02/wpf-mvvm-3d-model-viewer/">previous post</a> I showed you how to create a basic 3D model viewer in WPF using the MVVM pattern. In this post I&#8217;m going to show you how to take advantage of the MVVM design of this application by adding a couple more views (one view to move the camera, and one to change the mesh being viewed) and there will be one more view-model (for toggling the viewed mesh). </p>
<h3>The Camera  View </h3>
<p>Here is the xaml for the Camera Control Panel, this will use the CameraVM as its DataContext.</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>UserControl</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Class</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;TriRoot.Views.CameraPanel&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>:</span><span style='color:red;'>x</span><span style='color:blue;'>=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>StackPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DockPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>TextBlock</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Text</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;Rotation:&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Width</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;65&quot; /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>TextBlock</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> DockPanel.Dock</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;Right&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Width</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;65&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>Text</span><span style='color:blue;'>=&quot;{</span><span style='color:#A31515;'>Binding</span><span style='color:red;'> Rotation</span><span style='color:blue;'>}&quot; /&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Slider</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Name</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;RotationSlider&quot;</span><span style='font-size:8pt;font-family:"Courier New";'> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>Minimum</span><span style='color:blue;'>=&quot;0&quot;</span><span style='color:red;'> Maximum</span><span style='color:blue;'>=&quot;6.283&quot;</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>Value</span><span style='color:blue;'>=&quot;{</span><span style='color:#A31515;'>Binding</span><span style='color:red;'> Rotation</span><span style='color:blue;'>}&quot;/&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DockPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DockPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'> &gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>TextBlock</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Text</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;Up / Down:&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Width</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;65&quot; /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>TextBlock</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> DockPanel.Dock</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;Right&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Width</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;65&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>Text</span><span style='color:blue;'>=&quot;{</span><span style='color:#A31515;'>Binding</span><span style='color:red;'> UpPercent</span><span style='color:blue;'>}&quot; /&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Slider</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Name</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;UpPercentSlider&quot;</span><span style='font-size:8pt;font-family:"Courier New";'> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>Minimum</span><span style='color:blue;'>=&quot;-1&quot;</span><span style='color:red;'> Maximum</span><span style='color:blue;'>=&quot;1&quot;</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>Value</span><span style='color:blue;'>=&quot;{</span><span style='color:#A31515;'>Binding</span><span style='color:red;'> UpPercent</span><span style='color:blue;'>}&quot;/&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DockPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>StackPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;line-height:115%;font-family:"Courier New";color:#A31515;'>UserControl</span><span style='font-size:8pt;line-height:115%;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p>There is no additional code behind for this panel or the CameraVM. The sliders will update the values in the CameraVM through bindings when the user interacts with the sliders. </p>
<p>The following is an update to the test window to use this new panel. I&#8217;ve grayed out any code that was from the first post. </p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&lt;Window x:Class=&quot;TriRoot.Test.TestWindow&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>xmlns:views=&quot;clr-namespace:TriRoot.Views;assembly=TriRoot.Blog&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>xmlns:viewmodels=&quot;clr-namespace:TriRoot.ViewModels;assembly=TriRoot.Blog&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>Title=&quot;TriRoot.Test&quot; Height=&quot;300&quot; Width=&quot;300&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>&lt;Window.Resources&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>        </span>&lt;DataTemplate DataType=&quot;{x:Type viewmodels:ViewportVM}&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>            </span>&lt;views:ViewportPanel /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>        </span>&lt;/DataTemplate&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DataTemplate</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> DataType</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;{</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Type</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> viewmodels</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>CameraVM</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>}&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>views</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>CameraPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'> /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DataTemplate</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>&lt;/Window.Resources&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DockPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ContentPresenter</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Name</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;CameraVMContentPresenter&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> DockPanel.Dock</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;Top&quot;/&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&lt;ContentPresenter x:Name=&quot;ViewportVMContentPresenter&quot; /&gt;<span>        </span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DockPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&lt;/Window&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&nbsp;</span></p>
<p>And the CameraVM needs to be set as the Content of the new content presenter in the code behind </p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>CameraVM cameraVM = new CameraVM() { CameraData = cameraData };</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>MeshVM meshVM = new MeshVM() { MeshData = meshData };</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>ViewportVM viewportVM = new ViewportVM() </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>Camera = cameraVM, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>Mesh = meshVM </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>CameraVMContentPresenter.Content = cameraVM;</span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";color:gray;'>ViewportVMContentPresenter.Content = viewportVM;</span></p>
<p>Here&#8217;s a screenshot of the result:</p>
<p><img src="http://triroot.files.wordpress.com/2010/02/3dmodelviewercameracontrol.jpg"></p>
<p>In another post I have the details on how to implement a simple Cube Mesh against the IMeshData interface. The resulting class is the <a href="http://triroot.wordpress.com/2010/02/16/imeshdata-cube/">MeshDataCube</a>. Next I&#8217;m going to write a view model and view that allows the user to select between viewing a simple triangle or the MeshDataCube.<span>  </span></p>
<h3>The Mesh Editor View-Model</h3>
<p>The mesh editor will have a couple commands for toggling the mesh in use. These commands get bound to buttons, so that when a user clicks the button, ICommand.Execute gets called. The DelegateCommand is an implementation of ICommand that takes an Action that gets invoked in DelegateCommand.Execute, and a Func&lt;bool&gt; that gets invoked and returned in DelegateCommand.CanExecute.<span>  </span>In this implementation, I&#8217;m ignoring the parameters of Execute and CanExecute.</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>DelegateCommand</span> : <span style='color:#2B91AF;'>ICommand</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>Action</span> _executeAction;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>Func</span>&lt;<span style='color:blue;'>bool</span>&gt; _canExecuteFunc;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> DelegateCommand(<span style='color:#2B91AF;'>Action</span> executeAction)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>: <span style='color:blue;'>this</span>(executeAction, <span style='color:blue;'>null</span>)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> DelegateCommand(<span style='color:#2B91AF;'>Action</span> executeAction, <span style='color:#2B91AF;'>Func</span>&lt;<span style='color:blue;'>bool</span>&gt; canExecuteFunc)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_executeAction = executeAction;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_canExecuteFunc = canExecuteFunc;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>event</span> <span style='color:#2B91AF;'>EventHandler</span> CanExecuteChanged;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>void</span> Execute(<span style='color:blue;'>object</span> unused)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_executeAction();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>bool</span> CanExecute(<span style='color:blue;'>object</span> unused)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>return</span> _canExecuteFunc != <span style='color:blue;'>null</span> ? _canExecuteFunc() : <span style='color:blue;'>true</span>;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>void</span> FireCanExecuteChanged()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>if</span> (CanExecuteChanged != <span style='color:blue;'>null</span>)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>CanExecuteChanged(<span style='color:blue;'>this</span>, <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>EventArgs</span>());</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";'>}</span></p>
<p>The MeshEditor has two commands, one for switching to a triangle mesh, and one for switching to a cube mesh. The SelectedMesh property is a reference to the MeshVM which contains the MeshData that will be altered when a command executes. </p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>MeshEditorVM</span> : <span style='color:#2B91AF;'>DependencyObject</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>DelegateCommand</span> _triangleCommand;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>DelegateCommand</span> _cubeCommand;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> MeshEditorVM()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_triangleCommand = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>DelegateCommand</span>(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>MakeTriangle, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>CanMakeTriangle);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_cubeCommand = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>DelegateCommand</span>(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>MakeCube, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>CanMakeCube);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span>#region</span><span style='font-size:8pt;font-family:"Courier New";'> MeshVM SelectedMesh (DependencyProperty w/OnChanged)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>static</span> <span style='color:blue;'>readonly</span> <span style='color:#2B91AF;'>DependencyProperty</span> SelectedMeshDataProperty =</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyProperty</span>.Register(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#A31515;'>&quot;SelectedMesh&quot;</span>,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>typeof</span>(<span style='color:#2B91AF;'>MeshVM</span>),</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>typeof</span>(<span style='color:#2B91AF;'>MeshEditorVM</span>),</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>FrameworkPropertyMetadata</span>(OnSelectedMeshChanged));</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>MeshVM</span> SelectedMesh</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>get</span> { <span style='color:blue;'>return</span> (<span style='color:#2B91AF;'>MeshVM</span>)GetValue(SelectedMeshDataProperty); }</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>set</span> { SetValue(SelectedMeshDataProperty, <span style='color:blue;'>value</span>); }</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>protected</span> <span style='color:blue;'>static</span> <span style='color:blue;'>void</span> OnSelectedMeshChanged(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyObject</span> sender,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyPropertyChangedEventArgs</span> args)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>MeshEditorVM</span> me = (<span style='color:#2B91AF;'>MeshEditorVM</span>)sender;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>me.RefreshCommands();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span>#endregion</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>ICommand</span> TriangleCommand { <span style='color:blue;'>get</span> { <span style='color:blue;'>return</span> _triangleCommand; } }</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>ICommand</span> CubeCommand { <span style='color:blue;'>get</span> { <span style='color:blue;'>return</span> _cubeCommand; } }</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>private</span> <span style='color:blue;'>void</span> RefreshCommands()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_triangleCommand.FireCanExecuteChanged();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_cubeCommand.FireCanExecuteChanged();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>private</span> <span style='color:blue;'>void</span> MakeTriangle()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>if</span> (SelectedMesh != <span style='color:blue;'>null</span>)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>SelectedMesh.MeshData = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>MeshDataTriangle</span>(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(0.5, 0, 0), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(0, 0.5, 0), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(0, 0, 0.5));</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>RefreshCommands();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>private</span> <span style='color:blue;'>bool</span> CanMakeTriangle()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>return</span> SelectedMesh != <span style='color:blue;'>null</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>&amp;&amp; !(SelectedMesh.MeshData <span style='color:blue;'>is</span> <span style='color:#2B91AF;'>MeshDataTriangle</span>);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>private</span> <span style='color:blue;'>void</span> MakeCube()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>if</span> (SelectedMesh != <span style='color:blue;'>null</span>)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>SelectedMesh.MeshData = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>MeshDataCube</span>(1.0);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>RefreshCommands();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>private</span> <span style='color:blue;'>bool</span> CanMakeCube()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>return</span> SelectedMesh != <span style='color:blue;'>null</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>&amp;&amp; !(SelectedMesh.MeshData <span style='color:blue;'>is</span> <span style='color:#2B91AF;'>MeshDataCube</span>);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";'>}</span></p>
<p>Here is the xaml for the panel that will use the MeshEditorVM as it s DataContext.</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>UserControl</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Class</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;TriRoot.Views.MeshEditorPanel&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>:</span><span style='color:red;'>x</span><span style='color:blue;'>=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>StackPanel</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Background</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;LemonChiffon&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Margin</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;2&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Button</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Content</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;Triangle&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Command</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;{</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Binding</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> TriangleCommand</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>}&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Margin</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;2&quot;/&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Button</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Content</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;Cube&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Command</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;{</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Binding</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> CubeCommand</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>}&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Margin</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;2&quot;/&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>   </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>StackPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;line-height:115%;font-family:"Courier New";color:#A31515;'>UserControl</span><span style='font-size:8pt;line-height:115%;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p>Again, the following is an update to the test window to use this new panel.</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&lt;Window x:Class=&quot;TriRoot.Test.TestWindow&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>xmlns:views=&quot;clr-namespace:TriRoot.Views;assembly=TriRoot.Blog&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>xmlns:viewmodels=&quot;clr-namespace:TriRoot.ViewModels;assembly=TriRoot.Blog&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>Title=&quot;TriRoot.Test&quot; Height=&quot;300&quot; Width=&quot;300&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>&lt;Window.Resources&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>        </span>&lt;DataTemplate DataType=&quot;{x:Type viewmodels:ViewportVM}&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>            </span>&lt;views:ViewportPanel /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>        </span>&lt;/DataTemplate&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>        </span>&lt;DataTemplate DataType=&quot;{x:Type viewmodels:CameraVM}&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>            </span>&lt;views:CameraPanel /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>        </span>&lt;/DataTemplate&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DataTemplate</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> DataType</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;{</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Type</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> viewmodels</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>MeshEditorVM</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>}&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>views</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>MeshEditorPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'> /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DataTemplate</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>&lt;/Window.Resources&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>&lt;DockPanel&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ContentPresenter</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Name</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;MeshEditorVMContentPresenter&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> DockPanel.Dock</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;Right&quot;/&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>        </span>&lt;ContentPresenter x:Name=&quot;CameraVMContentPresenter&quot; DockPanel.Dock=&quot;Top&quot;/&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>        </span>&lt;ContentPresenter x:Name=&quot;ViewportVMContentPresenter&quot; /&gt;<span>        </span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>&lt;/DockPanel&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&nbsp;</span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";color:gray;'>&lt;/Window&gt;</span><span style='color:gray;'></span></p>
<p>And then in the code behind a MeshEditorVM gets hooked up to the new ContentPresenter. </p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>ICameraData cameraData = new CameraData();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>IMeshData meshData = new MeshDataTriangle(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>new Point3D(0.5, 0, 0), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>new Point3D(0, 0.5, 0), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>new Point3D(0, 0, 0.5));</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>CameraVM cameraVM = new CameraVM() { CameraData = cameraData };</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>MeshVM meshVM = new MeshVM() { MeshData = meshData };</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>ViewportVM viewportVM = new ViewportVM() </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>Camera = cameraVM, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>Mesh = meshVM </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#2B91AF;'>MeshEditorVM</span><span style='font-size:8pt;font-family:"Courier New";'> meshEditorVM = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>MeshEditorVM</span>() </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>SelectedMesh = meshVM </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>MeshEditorVMContentPresenter.Content = meshEditorVM;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>CameraVMContentPresenter.Content = cameraVM;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>ViewportVMContentPresenter.Content = viewportVM;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'>&nbsp;</span></p>
<p>And in case you missed it from my first post, here&#8217;s the final screenshot:</p>
<p><img src="http://triroot.files.wordpress.com/2009/12/3dmodelviewer.jpg"></p>
<p>BAM!</p>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/triroot.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/triroot.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/triroot.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/triroot.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/triroot.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/triroot.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/triroot.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/triroot.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/triroot.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/triroot.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/triroot.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/triroot.wordpress.com/61/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/triroot.wordpress.com/61/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/triroot.wordpress.com/61/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=triroot.wordpress.com&amp;blog=10727597&amp;post=61&amp;subd=triroot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://triroot.wordpress.com/2010/02/18/wpf-mvvm-3d-model-viewer-more-view-panels/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3860643072f113dc5b150969fae8df00?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">triroot</media:title>
		</media:content>

		<media:content url="http://triroot.files.wordpress.com/2010/02/3dmodelviewercameracontrol.jpg" medium="image" />

		<media:content url="http://triroot.files.wordpress.com/2009/12/3dmodelviewer.jpg" medium="image" />
	</item>
		<item>
		<title>Wpf MVVM 3D Model Viewer &#8211; IMeshData Cube</title>
		<link>http://triroot.wordpress.com/2010/02/16/imeshdata-cube/</link>
		<comments>http://triroot.wordpress.com/2010/02/16/imeshdata-cube/#comments</comments>
		<pubDate>Tue, 16 Feb 2010 05:00:54 +0000</pubDate>
		<dc:creator>triroot</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Cube mesh]]></category>

		<guid isPermaLink="false">http://triroot.wordpress.com/?p=48</guid>
		<description><![CDATA[In my last post I implemented a 3D Model Viewer that renders geometry from IMeshData. In the post I just rendered a simple triangle mesh. Here I&#8217;m going to implement a simple cube mesh. This implementation is designed to be easy to follow, and has not been optimized for saving memory. For reference, here is [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=triroot.wordpress.com&amp;blog=10727597&amp;post=48&amp;subd=triroot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div style="font-family:Calibri;font-size:11pt;">
<p>In my last post I implemented <span>a 3D</span> Model Viewer that renders geometry from <span>IMeshData</span>. In the post I just rendered a simple triangle mesh. Here I&#8217;m going to implement a simple cube mesh. This implementation is designed to be easy to follow, and has not been optimized for saving memory. </p>
<p>For reference, here is what the <span>IMeshData</span> looks like:</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>interface</span> <span style='color:#2B91AF;'>IMeshData</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>IEnumerable</span>&lt;<span style='color:#2B91AF;'>Point3D</span>&gt; Vertices { <span style='color:blue;'>get</span>; }</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>IEnumerable</span>&lt;<span style='color:blue;'>int</span>&gt; TriangleIndices { <span style='color:blue;'>get</span>; }</span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";'>}</span></p>
<p>I implemented a static Utility class that will describe the data needed for each cube face. <span> </span>The Contributions are the four corner points in 3D space for a face, and the <span>TriangleIndices</span> describes how to use those points to construct two triangles for the face</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>enum</span> <span style='color:#2B91AF;'>CubeFaceType</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>None,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>Left,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>Right,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>Top,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>Bottom,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>Front,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>Back,</span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";'>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>class</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:#2B91AF;'>CubeFaceUtil</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>internal</span> <span style='color:blue;'>static</span> <span style='color:#2B91AF;'>CubeFaceType</span>[] GetCubeFaces()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>CubeFaceType</span>[] </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#2B91AF;'>CubeFaceType</span>.Left, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#2B91AF;'>CubeFaceType</span>.Right, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#2B91AF;'>CubeFaceType</span>.Top, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#2B91AF;'>CubeFaceType</span>.Bottom, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#2B91AF;'>CubeFaceType</span>.Front, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#2B91AF;'>CubeFaceType</span>.Back </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>internal</span> <span style='color:blue;'>static</span> <span style='color:#2B91AF;'>Point3D</span>[] GetContributions(<span style='color:#2B91AF;'>CubeFaceType</span> type)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>switch</span> (type)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>case</span> <span style='color:#2B91AF;'>CubeFaceType</span>.Left: </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>[] </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, 1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, 1, 1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, -1, 1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, -1, -1) </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>case</span> <span style='color:#2B91AF;'>CubeFaceType</span>.Right: </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>[] </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, 1, 1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, 1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, -1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, -1, 1) </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>case</span> <span style='color:#2B91AF;'>CubeFaceType</span>.Top: </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>[] </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span>        </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, 1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, 1, -1),</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, 1, 1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, 1, 1) </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>case</span> <span style='color:#2B91AF;'>CubeFaceType</span>.Bottom: </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>[] </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, -1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, -1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, -1, 1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, -1, 1) </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>case</span> <span style='color:#2B91AF;'>CubeFaceType</span>.Front: </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>[] </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, 1, 1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, 1, 1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, -1, 1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, -1, 1) </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>case</span> <span style='color:#2B91AF;'>CubeFaceType</span>.Back: </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>[] </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, 1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, 1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(-1, -1, -1), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(1, -1, -1) </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>default</span>: </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span><span style='color:blue;'>throw</span> <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>ArgumentException</span>(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:#A31515;'>&quot;Unsupported CubeFaceType&quot;</span>, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                    </span><span style='color:#A31515;'>&quot;type&quot;</span>);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>internal</span> <span style='color:blue;'>static</span> <span style='color:blue;'>int</span>[] GetTriangleIndices()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:blue;'>int</span>[]</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>0, 3, 1,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>1, 3, 2</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>};</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";'>}</span></p>
<p>Now all that needs to be done is to iterate through the faces and add them to the <span>MeshDataCube</span>.</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>MeshDataCube</span> : <span style='color:#2B91AF;'>IMeshData</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> MeshDataCube(<span style='color:blue;'>double</span> cubeSize)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>double</span> halfFaceSize = cubeSize / 2;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>List</span>&lt;<span style='color:blue;'>int</span>&gt; allIndices = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>List</span>&lt;<span style='color:blue;'>int</span>&gt;();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>List</span>&lt;<span style='color:#2B91AF;'>Point3D</span>&gt; allVertices = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>List</span>&lt;<span style='color:#2B91AF;'>Point3D</span>&gt;();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>foreach</span> (<span style='color:#2B91AF;'>CubeFaceType</span> faceType <span style='color:blue;'>in</span> <span style='color:#2B91AF;'>CubeFaceUtil</span>.GetCubeFaces())</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>int</span>[] indices = <span style='color:#2B91AF;'>CubeFaceUtil</span>.GetTriangleIndices();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#2B91AF;'>Point3D</span>[] contributions = <span style='color:#2B91AF;'>CubeFaceUtil</span>.GetContributions(faceType);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#2B91AF;'>Point3D</span>[] positions = contributions.Select(p =&gt; p.Scale(halfFaceSize)).ToArray();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:green;'>// shift the indicies by the number of vertices already added.</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>allIndices.AddRange(indices.Select(i =&gt; i + allVertices.Count()));</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>allVertices.AddRange(positions);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>Vertices = allVertices;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>TriangleIndices = allIndices;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>&nbsp;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>IEnumerable</span>&lt;<span style='color:blue;'>int</span>&gt; TriangleIndices { <span style='color:blue;'>get</span>; <span style='color:blue;'>protected</span> <span style='color:blue;'>set</span>; }</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>  </span><span>  </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>IEnumerable</span>&lt;<span style='color:#2B91AF;'>Point3D</span>&gt; Vertices { <span style='color:blue;'>get</span>; <span style='color:blue;'>protected</span> <span style='color:blue;'>set</span>; }</span></p>
<p><span style='font-size:8pt;line-height:115%;font-family:"Courier New";'>}</span></p>
<p>BAM!</p>
<p>&nbsp;</p>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/triroot.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/triroot.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/triroot.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/triroot.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/triroot.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/triroot.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/triroot.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/triroot.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/triroot.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/triroot.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/triroot.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/triroot.wordpress.com/48/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/triroot.wordpress.com/48/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/triroot.wordpress.com/48/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=triroot.wordpress.com&amp;blog=10727597&amp;post=48&amp;subd=triroot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://triroot.wordpress.com/2010/02/16/imeshdata-cube/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3860643072f113dc5b150969fae8df00?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">triroot</media:title>
		</media:content>
	</item>
		<item>
		<title>Wpf MVVM 3D Model Viewer</title>
		<link>http://triroot.wordpress.com/2009/12/02/wpf-mvvm-3d-model-viewer/</link>
		<comments>http://triroot.wordpress.com/2009/12/02/wpf-mvvm-3d-model-viewer/#comments</comments>
		<pubDate>Wed, 02 Dec 2009 05:10:27 +0000</pubDate>
		<dc:creator>triroot</dc:creator>
				<category><![CDATA[WPF]]></category>
		<category><![CDATA[3D Model Viewer]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[mvvm]]></category>

		<guid isPermaLink="false">http://triroot.wordpress.com/?p=4</guid>
		<description><![CDATA[The basics for setting up a 3D model viewer using the MVVM pattern in a WPF application.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=triroot.wordpress.com&amp;blog=10727597&amp;post=4&amp;subd=triroot&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div style="font-family:Calibri;font-size:11pt;">
<h3>Introduction</h3>
<p style='margin:0;'>In this post I’m going to walk you through a few of the basics for setting up a 3D model viewer using the MVVM (Model View View-Model) pattern in a WPF (Windows Presentation Foundation) application. I’ll show you how to set up a view port, camera control and a simple mesh.</p>
</p>
<p><img src="http://triroot.files.wordpress.com/2009/12/3dmodelviewer.jpg"></p>
<p style='margin:0;'>This post assumes you have a basic understanding of WPF, MVVM, and 3D modeling.</p>
</p>
<h3>Background</h3>
<p style='margin:0;'>There are a couple of WPF classes that it would be worth quickly going to MSDN and browsing over their examples.</p>
</p>
<p style='margin:0;'><a href="http://msdn.microsoft.com/en-us/library/system.windows.controls.viewport3d.aspx">Viewport3D</a> – provides a rendering surface for 3D content.</p>
<p style='margin:0;'><a href="http://msdn.microsoft.com/en-us/library/system.windows.media.media3d.camera.aspx">Camera</a> – an abstract class that represents the viewing position and direction in 3D space. It describes how a 3D model is projected onto <span class="GramE">a 2D</span> visual.</p>
<p style='margin:0;'><a href="http://msdn.microsoft.com/en-us/library/system.windows.media.media3d.visual3d.aspx">Visual3D</a> – an abstract class that provides services and properties common to visual 3D objects.</p>
</p>
<h3>Classes and Interfaces </h3>
<p style='margin:0;'>The interfaces and classes that I’ll be implementing are the following:</p>
</p>
<p style='margin:0;'>IMeshData – a simple interface that represents a mesh’s model</p>
<p style='margin:0;'>ICameraData – a simple interface that represents the camera’s model</p>
<p style='margin:0;'>MeshVM – a class that represents the mesh’s view-model</p>
<p style='margin:0;'>CameraVM – a class that represents the camera’s view-model</p>
<p style='margin:0;'>ViewportPanel – the WPF view for the camera and meshes.</p>
</p>
<p style='margin:0;'>I’ve chosen to use interfaces for my models because it gives the user the flexibility to implement their own data, or to wrap external classes, or both. </p>
<h3>The Mesh Model</h3>
<p style='margin:0;'>I’m keeping the model very simple, if you want get a bit fancier with this interface, you could add <span class="SpellE">normals</span>, texture mapping, material metadata, and so on. The class that implements the mesh model interface is just a simple triangle mesh. </p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>interface</span> <span style='color:#2B91AF;'>IMeshData</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>IEnumerable</span>&lt;<span style='color:#2B91AF;'>Point3D</span>&gt; Vertices { <span style='color:blue;'>get</span>; }</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>IEnumerable</span>&lt;<span style='color:blue;'>int</span>&gt; TriangleIndices { <span style='color:blue;'>get</span>; }</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>MeshDataTriangle</span> : <span style='color:#2B91AF;'>IMeshData</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:#2B91AF;'>List</span>&lt;<span style='color:#2B91AF;'>Point3D</span>&gt; _vertices = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>List</span>&lt;<span style='color:#2B91AF;'>Point3D</span>&gt;();</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> MeshDataTriangle(<span style='color:#2B91AF;'>Point3D</span> one, <span style='color:#2B91AF;'>Point3D</span> two, <span style='color:#2B91AF;'>Point3D</span> three)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_vertices.Add(one);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_vertices.Add(two);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>_vertices.Add(three);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>IEnumerable</span>&lt;<span style='color:#2B91AF;'>Point3D</span>&gt; Vertices </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>get</span> { <span style='color:blue;'>return</span> _vertices; } </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>IEnumerable</span>&lt;<span style='color:blue;'>int</span>&gt; TriangleIndices </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>get</span> { <span style='color:blue;'>return</span> <span style='color:blue;'>new</span> <span style='color:blue;'>int</span>[] { 0, 1, 2 }; } </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<h3>The Camera Model</h3>
<p style='margin:0;'>I’m using a pretty straight forward representation of a camera. In this case the Rotation represents the X and Z coordinates around a center point, and the UpPercent represents how high the camera is above (or below) the origin. </p>
</p>
<p><img src="http://triroot.files.wordpress.com/2009/11/cameradescription.jpg"></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>interface</span> <span style='color:#2B91AF;'>ICameraData</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:gray;'>///</span><span style='color:green;'> </span><span style='color:gray;'>&lt;summary&gt;</span><span style='color:green;'> value between 0 (included) and 2*PI (excluded) </span><span style='color:gray;'>&lt;/summary&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>double</span> Rotation { <span style='color:blue;'>get</span>; }</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:gray;'>///</span><span style='color:green;'> </span><span style='color:gray;'>&lt;summary&gt;</span><span style='color:green;'> value between -1.0 (looking straight up) and 1.0 (looking straight down) </span><span style='color:gray;'>&lt;/summary&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>double</span> UpPercent { <span style='color:blue;'>get</span>; }</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>bool</span> SetRotation(<span style='color:blue;'>double</span> rotation);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>bool</span> SetUpPercent(<span style='color:blue;'>double</span> upPercent);</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>CameraData</span> : <span style='color:#2B91AF;'>ICameraData</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>double</span> Rotation { <span style='color:blue;'>get</span>; <span style='color:blue;'>protected</span> <span style='color:blue;'>set</span>; }</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>double</span> UpPercent { <span style='color:blue;'>get</span>; <span style='color:blue;'>protected</span> <span style='color:blue;'>set</span>; }</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>bool</span> SetRotation(<span style='color:blue;'>double</span> rotation)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>Rotation = rotation;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>return</span> <span style='color:blue;'>true</span>;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>bool</span> SetUpPercent(<span style='color:blue;'>double</span> upPercent)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>UpPercent = upPercent;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>return</span> <span style='color:blue;'>true</span>;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<p style='margin:0;'>I decided to make the SetRotation and SetUpPercent methods have return type bool, because I can see a case where the camera is locked in place and not modifiable by the user. However, in my example here I’m not doing anything interesting like that. </p>
</p>
<h3>The View-Models </h3>
<p style='margin:0;'>Okay, now onto something a bit more interesting. The view-model is the glue between the model and the view. In the case of the MeshVM, the model data gets set as input, and then it is automatically converted to something that can be bound directly to the view. I’ve seen implementations of the View-Model that implement INotifyPropertyChanged, or have a ViewModelBase class, but I prefer just having the view model inherit from DependencyObject so that I can use the sweet sweet goodness of Dependency Properties. </p>
</p>
<p style='margin:0;'>With the MeshVM, the MeshData property is a reference to the model and the Geometry property is what the view can be bound to. When the MeshData is changed, the Geometry will be generated by a call to the RefreshGeometry method. </p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>MeshVM</span> : <span style='color:#2B91AF;'>DependencyObject</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span>#region</span><span style='font-size:8pt;font-family:"Courier New";'> IMeshData MeshData (DependencyProperty w/OnMeshDataChanged)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>static</span> <span style='color:blue;'>readonly</span> <span style='color:#2B91AF;'>DependencyProperty</span> MeshDataProperty = </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyProperty</span>.Register(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#A31515;'>&quot;MeshData&quot;</span>, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>typeof</span>(<span style='color:#2B91AF;'>IMeshData</span>), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>typeof</span>(<span style='color:#2B91AF;'>MeshVM</span>), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>FrameworkPropertyMetadata</span>(OnMeshDataChanged));</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>IMeshData</span> MeshData </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>get</span> { <span style='color:blue;'>return</span> (<span style='color:#2B91AF;'>IMeshData</span>)GetValue(MeshDataProperty); } </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>set</span> { SetValue(MeshDataProperty, <span style='color:blue;'>value</span>); } </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>protected</span> <span style='color:blue;'>static</span> <span style='color:blue;'>void</span> OnMeshDataChanged(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyObject</span> sender, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyPropertyChangedEventArgs</span> args)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>MeshVM</span> me = (<span style='color:#2B91AF;'>MeshVM</span>)sender;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>IMeshData</span> newMeshData = (<span style='color:#2B91AF;'>IMeshData</span>)args.NewValue;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>me.RefreshGeometry(newMeshData);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span>#endregion</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span>#region</span><span style='font-size:8pt;font-family:"Courier New";'> MeshGeometry3D Geometry (DependencyProperty)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:blue;'>static</span> <span style='color:blue;'>readonly</span> <span style='color:#2B91AF;'>DependencyProperty</span> GeometryProperty = </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyProperty</span>.Register(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:#A31515;'>&quot;Geometry&quot;</span>, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>typeof</span>(<span style='color:#2B91AF;'>MeshGeometry3D</span>), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>typeof</span>(<span style='color:#2B91AF;'>MeshVM</span>));</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> <span style='color:#2B91AF;'>MeshGeometry3D</span> Geometry </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>get</span> { <span style='color:blue;'>return</span> (<span style='color:#2B91AF;'>MeshGeometry3D</span>)GetValue(GeometryProperty); } </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>protected</span> <span style='color:blue;'>set</span> { SetValue(GeometryProperty, <span style='color:blue;'>value</span>); } </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span>#endregion</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>private</span> <span style='color:blue;'>void</span> RefreshGeometry(<span style='color:#2B91AF;'>IMeshData</span> mesh)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>MeshGeometry3D</span> geometry = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>MeshGeometry3D</span>();</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>geometry.Positions = mesh != <span style='color:blue;'>null</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>? <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3DCollection</span>(mesh.Vertices) </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>: <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3DCollection</span>();</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>geometry.TriangleIndices = mesh != <span style='color:blue;'>null</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>         </span><span>   </span>? <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Int32Collection</span>(mesh.TriangleIndices) </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>: <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Int32Collection</span>();</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>Geometry = geometry;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<p style='margin:0;'>Next is the CameraVM. This is a bit more complicated than the MeshVM, but the idea is the same. In this case there are three variables that get bound to the view – the camera Position, the UpDirection and the LookDirection. I’ve also provided two additional variables that can be used to modify the camera’s data – the Rotation and the UpPercent. Notice that when the CameraData is set, the _isSettingData is set to true, that way the OnChanged events for the Rotation and UpPercent get skipped and RefreshCamera only gets called once. </p>
</p>
<p style='margin:0;'>For the sake of space, I’m going to collapse the dependency property regions because it’s mostly just boiler plate code anyway. I’ll leave the changed events since that’s where all the interesting stuff happens.</p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>CameraVM</span> : <span style='color:#2B91AF;'>DependencyObject</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>bool</span> _isSettingData;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:gray;'>ICameraData CameraData (DependencyProperty w/OnCameraDataChanged)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>protected</span> <span style='color:blue;'>static</span> <span style='color:blue;'>void</span> OnCameraDataChanged(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyObject</span> sender, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyPropertyChangedEventArgs</span> args)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>CameraVM</span> me = (<span style='color:#2B91AF;'>CameraVM</span>)sender;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>ICameraData</span> newCameraData = (<span style='color:#2B91AF;'>ICameraData</span>)args.NewValue;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>me._isSettingData = <span style='color:blue;'>true</span>;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>me.Rotation = newCameraData.Rotation;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>me.UpPercent = newCameraData.UpPercent;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>me._isSettingData = <span style='color:blue;'>false</span>;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>me.RefreshCamera(newCameraData);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:gray;'>double Rotation (DependencyProperty w/OnRotationChanged)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>protected</span> <span style='color:blue;'>static</span> <span style='color:blue;'>void</span> OnRotationChanged(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyObject</span> sender, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyPropertyChangedEventArgs</span> args)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>CameraVM</span> me = (<span style='color:#2B91AF;'>CameraVM</span>)sender;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>if</span> (!me._isSettingData)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>double</span> newRotation = (<span style='color:blue;'>double</span>)args.NewValue;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>if</span> (me.CameraData != <span style='color:blue;'>null</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>&amp;&amp; me.CameraData.SetRotation(newRotation))</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>me.RefreshCamera(me.CameraData);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:gray;'>double UpPercent (DependencyProperty w/OnUpPercentChanged)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>protected</span> <span style='color:blue;'>static</span> <span style='color:blue;'>void</span> OnUpPercentChanged(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyObject</span> sender, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>DependencyPropertyChangedEventArgs</span> args)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>CameraVM</span> me = (<span style='color:#2B91AF;'>CameraVM</span>)sender;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>if</span> (!me._isSettingData)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>double</span> newUpPercent = (<span style='color:blue;'>double</span>)args.NewValue;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>if</span> (me.CameraData != <span style='color:blue;'>null</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>&amp;&amp; me.CameraData.SetUpPercent(newUpPercent))</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>me.RefreshCamera(me.CameraData);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>}</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:gray;'>Point3D Position (DependencyProperty)</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>Vector3D LookDirection (DependencyProperty)</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>Vector3D UpDirection (DependencyProperty)</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>private</span> <span style='color:blue;'>void</span> RefreshCamera(<span style='color:#2B91AF;'>ICameraData</span> cameraData)</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>double</span> rotation = cameraData != <span style='color:blue;'>null</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>? cameraData.Rotation </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>: 0;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>double</span> cameraX = <span style='color:#2B91AF;'>Math</span>.Sin(rotation);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>double</span> cameraZ = <span style='color:#2B91AF;'>Math</span>.Cos(rotation);</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>double</span> upDownPercent = cameraData != <span style='color:blue;'>null</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>? cameraData.UpPercent </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>: 0;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:blue;'>double</span> rotationPercent = 1.0 &#8211; <span style='color:#2B91AF;'>Math</span>.Abs(upDownPercent);</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>Vector3D</span> straightUpVector = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Vector3D</span>(0.0, 1.0, 0.0);</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>Vector3D</span> rotationVector = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Vector3D</span>(cameraX, 0.0, cameraZ);</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>Vector3D</span> rightVector = <span style='color:#2B91AF;'>Vector3D</span>.CrossProduct(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>straightUpVector, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>rotationVector);</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>Vector3D</span> positionVector = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Vector3D</span>(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>rotationVector.X * rotationPercent,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>straightUpVector.Y * upDownPercent,</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>rotationVector.Z * rotationPercent);</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>Vector3D</span> lookVector = <span style='color:#2B91AF;'>Vector3D</span>.Subtract(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>         </span><span>   </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Vector3D</span>(), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>positionVector);</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>Vector3D</span> upVector = <span style='color:#2B91AF;'>Vector3D</span>.CrossProduct(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>positionVector, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>rightVector);</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>upVector.Normalize();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>lookVector.Normalize();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>positionVector.Normalize();</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>positionVector = positionVector * 2.5;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>Position = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>positionVector.X, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>positionVector.Y, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>positionVector.Z);</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>LookDirection = lookVector;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>UpDirection = upVector;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<p style='margin:0;'>The camera will always be looking at the origin, so in figuring out the Position of the camera, the LookDirection can easily be calculated by subtracting the Position vector from the zero vector. The UpDirection can be calculated by keeping track of the right vector and then crossing it with the final Position vector.</p>
</p>
<p><img src="http://triroot.files.wordpress.com/2009/11/rotationvector.jpg"><br />
<img src="http://triroot.files.wordpress.com/2009/11/positionvector.jpg"></p>
<p style='margin:0;'>There needs to be a view model that ties all the other view models together.<span>  </span>So here is the ViewportVM, it has two dependency properties, one for the MeshVM and one for the CameraVM.<span style='font-size:8pt;font-family:"Courier New";'></span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>ViewportVM</span> : <span style='color:#2B91AF;'>DependencyObject</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>CameraVM Camera (DependencyProperty)</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:gray;'><span>    </span>MeshVM Mesh (DependencyProperty)</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<h3>The View</h3>
<p style='margin:0;'>Now we need a view that all this data can hooked up to. The ViewportPanel is a simple UserControl that will contain the 3D view port, the camera, and one mesh. I’m also going to cheat a little and just throw in a couple lights to beautify the scene. The code behind is literally just what you get when you use the VisualStudio UserControl template. </p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>partial</span> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>ViewportPanel</span> : <span style='color:#2B91AF;'>UserControl</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span><span style='color:blue;'>public</span> ViewportPanel()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>InitializeComponent();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<p style='margin:0;'>The ViewportPanel will use the ViewportVM as the DataContext. So in the xaml, the Mesh and Camera get bound to the MeshVM and CameraVM respectively.</p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>UserControl</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Class</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;TriRoot.Views.ViewportPanel&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>:</span><span style='color:red;'>x</span><span style='color:blue;'>=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;&gt;</span></span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Viewport3D</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Viewport3D.Camera</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>PerspectiveCamera</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Name</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;camera&quot;</span><span style='font-size:8pt;font-family:"Courier New";'> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>Position</span><span style='color:blue;'>=&quot;{</span><span style='color:#A31515;'>Binding</span><span style='color:red;'> Camera</span><span style='color:blue;'>.</span><span style='color:red;'>Position</span><span style='color:blue;'>}&quot;</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>LookDirection</span><span style='color:blue;'>=&quot;{</span><span style='color:#A31515;'>Binding</span><span style='color:red;'> Camera</span><span style='color:blue;'>.</span><span style='color:red;'>LookDirection</span><span style='color:blue;'>}&quot;</span> </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>               </span><span style='color:red;'><span> </span>UpDirection</span><span style='color:blue;'>=&quot;{</span><span style='color:#A31515;'>Binding</span><span style='color:red;'> Camera</span><span style='color:blue;'>.</span><span style='color:red;'>UpDirection</span><span style='color:blue;'>}&quot;/&gt;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Viewport3D.Camera</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelUIElement3D</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Name</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;model&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelUIElement3D.Model</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>                </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>GeometryModel3D</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Geometry</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;{</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Binding</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Mesh</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>.</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Geometry</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>}&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>                    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>GeometryModel3D.Material</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>                        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DiffuseMaterial</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Brush</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;LightGray&quot; /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>                    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>GeometryModel3D.Material</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>                </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>GeometryModel3D</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelUIElement3D.Model</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelUIElement3D</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelVisual3D</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelVisual3D.Content</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>                </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>PointLight</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Color</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;White&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Position</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;9, 12, 10&quot; /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelVisual3D.Content</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelVisual3D</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelVisual3D</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelVisual3D.Content</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>                </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>PointLight</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Color</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;White&quot;</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> Position</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;-10, -12, -8&quot; /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>            </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelVisual3D.Content</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ModelVisual3D</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Viewport3D</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
</p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>UserControl</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
</p>
<p style='margin:0;'>Almost done… The last and final step is to write a test window where an instance of each of these objects is created.<span>  </span>I’ve chosen to use a ContentPresenter so that when I add a view model as its content, the view model is automatically set as the content’s DataContext. This way a designer can go in and modify the ViewportVM DataTemplate without having to worry about what’s happening in the code behind. Here it is:</p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Window</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Class</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;TriRoot.Test.TestWindow&quot;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>:</span><span style='color:red;'>x</span><span style='color:blue;'>=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>:</span><span style='color:red;'>views</span><span style='color:blue;'>=&quot;clr-namespace:TriRoot.Views;assembly=TriRoot.Blog&quot;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>xmlns</span><span style='color:blue;'>:</span><span style='color:red;'>viewmodels</span><span style='color:blue;'>=&quot;clr-namespace:TriRoot.ViewModels;assembly=TriRoot.Blog&quot;</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span style='color:red;'><span> </span>Title</span><span style='color:blue;'>=&quot;TriRoot.Test&quot;</span><span style='color:red;'> Height</span><span style='color:blue;'>=&quot;300&quot;</span><span style='color:red;'> Width</span><span style='color:blue;'>=&quot;300&quot;&gt;</span></span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Window.Resources</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DataTemplate</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> DataType</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;{</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Type</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> viewmodels</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>ViewportVM</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>}&quot;&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>views</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ViewportPanel</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'> /&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>DataTemplate</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Window.Resources</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>    </span></span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>ContentPresenter</span><span style='font-size:8pt;font-family:"Courier New";color:red;'> x</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>:</span><span style='font-size:8pt;font-family:"Courier New";color:red;'>Name</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>=&quot;ViewportVMContentPresenter&quot; /&gt;</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'><span>        </span></span></p>
</p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&lt;/</span><span style='font-size:8pt;font-family:"Courier New";color:#A31515;'>Window</span><span style='font-size:8pt;font-family:"Courier New";color:blue;'>&gt;</span></p>
</p>
<p style='margin:0;'><span> </span>And the code behind:</p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";color:blue;'>public</span><span style='font-size:8pt;font-family:"Courier New";'> <span style='color:blue;'>partial</span> <span style='color:blue;'>class</span> <span style='color:#2B91AF;'>TestWindow</span> : System.Windows.<span style='color:#2B91AF;'>Window</span></span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>   </span><span> </span><span style='color:blue;'>public</span> TestWindow()</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>{</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>InitializeComponent();</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>ICameraData</span> cameraData = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>CameraData</span>();</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>IMeshData</span> meshData = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>MeshDataTriangle</span>(</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(0.5, 0, 0), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(0, 0.5, 0), </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span><span style='color:blue;'>new</span> <span style='color:#2B91AF;'>Point3D</span>(0, 0, 0.5));</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>CameraVM</span> cameraVM = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>CameraVM</span>() { CameraData = cameraData };</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>MeshVM</span> meshVM = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>MeshVM</span>() { MeshData = meshData };</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span><span style='color:#2B91AF;'>ViewportVM</span> viewportVM = <span style='color:blue;'>new</span> <span style='color:#2B91AF;'>ViewportVM</span>() </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>{ </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>Camera = cameraVM, </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>                </span>Mesh = meshVM </span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>            </span>};</span></p>
</p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>        </span>ViewportVMContentPresenter.Content = viewportVM;</span></p>
<p style='line-height:normal;margin:0;'><span style='font-size:8pt;font-family:"Courier New";'><span>    </span>}</span></p>
<p style='margin:0;'><span style='font-size:8pt;font-family:"Courier New";'>}</span></p>
</p>
<p style='margin:0;'>Here&#8217;s a sample screenshot of the result:</p>
</p>
<p><img src="http://triroot.files.wordpress.com/2009/12/3dmodelviewerbasic.jpg"></p>
<p style='margin:0;'>Well, that&#8217;s it for now. The basic framework is in place to fully take advantage of a MVVM design, and in my next post I&#8217;ll do just that. I&#8217;ll walk you through the implementation of the top camera control panel and the side mesh selector panel that I teased you with in the introduction of this post.</p>
</p>
<p style='margin:0;'>BAM!</p>
</div>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/triroot.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/triroot.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/triroot.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/triroot.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/triroot.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/triroot.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/triroot.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/triroot.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/triroot.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/triroot.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/triroot.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/triroot.wordpress.com/4/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/triroot.wordpress.com/4/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/triroot.wordpress.com/4/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=triroot.wordpress.com&amp;blog=10727597&amp;post=4&amp;subd=triroot&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://triroot.wordpress.com/2009/12/02/wpf-mvvm-3d-model-viewer/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/3860643072f113dc5b150969fae8df00?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">triroot</media:title>
		</media:content>

		<media:content url="http://triroot.files.wordpress.com/2009/12/3dmodelviewer.jpg" medium="image" />

		<media:content url="http://triroot.files.wordpress.com/2009/11/cameradescription.jpg" medium="image" />

		<media:content url="http://triroot.files.wordpress.com/2009/11/rotationvector.jpg" medium="image" />

		<media:content url="http://triroot.files.wordpress.com/2009/11/positionvector.jpg" medium="image" />

		<media:content url="http://triroot.files.wordpress.com/2009/12/3dmodelviewerbasic.jpg" medium="image" />
	</item>
	</channel>
</rss>
