Jaime Rodriguez
On Windows Store apps, Windows Phone, HTML and XAML

  • Jaime Rodriguez

    WPF discussions 090626


    Emails from our MS internal discussions. Lots a great tips.

    Subject: Advise for running WPF apps over Citrix

    All versions of WPF since WPF 3.5 SP1 have remoted (both with Remote Desktop and Terminal Server) using Bitmap Remoting.

    Bitmap remoting works as follows:

    • The application is rendered on the server using WPF’s software rasterizer
    • As the application runs, the server keeps track of which regions of the application’s window are newly dirty and need to be updated
    • When a region needs to be updated, the server creates a compressed bitmap of just the dirty region and sends that to the client
    • Once the client has drawn that bitmap to the appropriate place on its own window, the client window is up-to-date

    Given how this remoting mechanism works, performance can be maximized in several ways:

    • Dirty regions should be kept as small as possible so the least amount of data is sent over the wire
    • Ambient animations should be turned off
      • For instance, setting a window background to an animating gradient would cause the entire window to be invalidated / redrawn every frame
    • The system does not optimize away occluded parts of the application
      • For instance, an animation that is completely hidden behind some other opaque element will still cause dirty region invalidation / bitmap generation to occur.  Remove these from your application.
    • Dirty regions should be created as infrequently as possible
      • Turn off as many animations as possible
      • For those animations that can’t be eliminated completely, lower the animation framerate using the DesiredFramerate property
    • Dirty Region Bitmaps should be as simple as possible to maximize their compression
      • Application running over TS should favor solid colors over gradients or other exotic fills (unnecessary images, etc), especially for application pieces that will be redrawn frequently
    • Avoid operations that are especially slow when rendered in software
      • BitmapEffects / Effects / ShaderEffects, especially blurs and drop shadows with large radii, are quite slow in software
      • 3D – the 3D software rasterizer is substantially slower than rendering in hardware

    Subject: Is there any support in WPF for “bottom-up” bitmaps?
    I’m using BitmapSource.Create with an unmanaged memory buffer. The buffer comes from a Win32 DIBSection with a +ve height, which indicates a bottom-up DIB.

    Wrap it in a TransformedBitmap. 
    return new TransformedBitmap(bmp, new ScaleTransform(1,-1));

    [extra tip]
    Note that I think each call to CopyPixels() on the TransformedBitmap will run the scale transformation again. You can avoid this by caching the result in a CachedBitmap and using the CB instead

    Subject: Getting DependencyProperty value from WinDBG
    I have a dump of a WPF process and am trying to get the value of a DependencyProperty of UIElement.  Does anybody know how this can be done?

    1. Pull out the value of _packedData.
    2. _packedData & 0x0000FFFF will give you the GlobalIndex.
    3. Go to the DependencyObject on which you want to query the property and get access to the _effectiveValues array.
    4. Go through the EffectiveValueEntry objects, looking at the _propertyIndex field until it matches the index you calculated in step 2 (the array should be sorted by property index).
    5. _value is the value of the property on that DependencyObject.

    Subject:  Difference between nulll and x:Null for brushes

    I know there is a difference but I can’t remember. I think it had something to do with hit testing (but I can’t remember for sure).

    No difference.  You're probably thinking of null (No hit test) versus Transparent (Can be hit).

    Subject: Disable auto-word selection in FlowDocumentViewer
    How can I make FlowDocumentViewer select character by character when I use the mouse?

    For FlowDocumentPageViewer, you can use flowDocumentPageViewer.SetValue(TextBoxBase.AutoWordSelectionProperty, false). FlowDocumentScrollViewer doesn’t auto-select words by default.

    Internally, the selection code shared by text boxes and FlowDocument viewers relies on TextBoxBase.AutoWordSelectionProperty. We don’t currently expose the property on anything other than TextBoxBase.

    Subject: Blend units.
    Any reason why Blend3 outputs font size in WPF “units” and not the actual pt value. If I change the FontSize on a TextBlock to “11pt”, 14.667 is written out.

    Blend 2 always displayed text units in pixels. This was confusing to most designers who are used to thinking of fonts in terms of points. In Blend 3 we added an option where you can choose whether you want points or pixels as your display in the Property panel. This is under the Units tab in the Options dialog.

    In terms of the XAML output, we had wanted to output the same units as shown in the UI but Silverlight does not support the pt syntax in XAML so we decided (for cost and consistency reasons) to just leave it as pixels in the XAML for V3.  It is something for us to consider improving in the future though.

    Subject: Disable IME on TextBox
    Is there a setting to disable using IME on a textbox, or some other means of not allowing a user to use it?

    <TextBox InputMethod.IsInputMethodEnabled=”false” />

    Subject: DateTime property in the Properties editor of Blend
    I have a question regarding how Blend handles a control property which is of type System.DateTime.  I am trying to understand how the property editor would interpret a string such as 20/05/2001. Would it take into account the regional settings of the computer or is it tied up with the implementation of the control itself?

    Blend will use a text editor to read and display DateTimes, and will parse input based on the locale settings of your machine.  In xaml, it is always stored in an invariant format(year-month-day).

    Subject:  (summarized) issue w/ WPF not matching GDI on how a custom font is rendered

    There is no expectation that WPF font rasterization will match GDI\GDI+ rasterization. For example if the font does not have italic or bold variants GDI will emulate bold and italic WPF will not.

    Subject: DPI interop issues...

    I have a drag/drop gesture that draws a drag/drop feedback in a transparent WPF window. The problem is in tracking the mouse position I had to use interop to Win32.GetCursorPos and that works, when the operating system is in 96 DPI mode.  But when you change the OS DPI to something else, like 120 or 150 DPI then this doesn’t work because positioning the transparent WPF drag/drop feedback window requires WPF device independent coordinates (essentially 96 DPI) so I need to do a conversion

    Have you looked at Visual.PointFromScreen?  It can be used to convert screen coordinates from APIs such as GetCursorPos into Device Independent Units

    Subject: Game loops in WPF?
    wondering how easy it would be to write a custom "game loop" within the WPF framework. By game loop, I mean pumping my own events on a custom Dispatcher so I can control the framerate of my app.

    You can write your own message pump. Just don't call Dispatcher.Run. You need to pump messages, and you need to call ComponentDispatcher.RaiseThreadMessage as appropriate. Use reflector to see what Dispatcher.PushFrame does.

    Of course, this still may not give you what you want for a "game loop"...

    Subject: Is there a way to prevent exception if DataContext is null?

    This is just an example.

    I have a Image which is Databind to some dynamic source (image source) and it works fine and it is all done in xaml. Can we provide some defaule image source incase DataContext becomes null?


    FallbackValue is your friend: http://msdn.microsoft.com/en-us/library/system.windows.data.bindingbase.fallbackvalue.aspx

    Subject: Listening to selective ETW Events

    I’m writing performance tests where we want to listen to the WClientUceNotifyPresent ETW event to calculate frame rates.  However, I haven’t found provider flags to listen to it, along with a limited set of other events.


    With WPF 3.0-3.5 you unfortunately don’t have a lot of options.  You should make sure that you’re using verbosity level 4 (as opposed to 5).

    If you’re on CLR 4.0 we have much more granular flags so you’ll be able to turn on a flag specifically for Graphics related events which should help .  If you have a recent drop (post Beta1) you should find our event manifest installed in \windows\microsoft.net\framework\v4.0\wpf\wpf-etw.man which lists the available flags.  You will need either flag 1 `General` or flag 0x1000 `Graphics` depending on what drop you have.

    Subject: Way to check if an UIElement is visible in ScrollViewer

    Is there any way to check if an UI element is already showing in a scroll viewer?

    [Not right one, but works]
    Use reflection to invoke ScrollViewer.IsInViewport method?

    I wouldn’t recommend this for production code.
    Is there a reason you don’t want to call BringIntoView on elements that are already visible? All handlers of RequestBringIntoView I know of no-op on visible elements.


  • Jaime Rodriguez

    New release of WPF Toolkit, now with charts!


    The June release of the WPF toolkit went live today, it now includes the charts imagethat come with the Silverlight toolkit.

    David Anson has the scoop and a great sample on the charts

    The other controls (Datagrid, VSM, and DatePicker) also include a few minor fixes (check the release notes).
    There is not an update for the WPF ribbon; we are still hopingthe update to ribbon comes after (or around same time) as .NET4 beta2. 

    Enjoy the charts and the new toolkit, please don’t forget to send feedback.


    PS. – Congrats to David Anson for the release; he has been the biggest advocate for the charts making it into WPF. I am sure he put some ‘over-time’ given how much they are doing with the Silverlight control toolkit too.  Thanks David!

  • Jaime Rodriguez

    THANKS CHICAGO. Here is the content.


    Last friday, we had the pleasure of delivering the last stop in the WPF for LOB tour: Chicago. ChicagoXamlized


    The training was very lively, with lots of people from all over the mid-west, and a few people from other further places…  It was a lot of fun at a good location (despite a shaky start with a microphone, that only lasted 45 mins ).  Definitely a good way to finish the tour..

    The content for Chicago is now posted:  Decks  and demos 


    Thanks to all the Chicago attendees!!


    And thanks to every one else who helped us with the tour.  This has been a lot of fun and very enlightening and inspiring to us.




  • Jaime Rodriguez



    Last week’s stop in the WPF for LOB tour was Phoenix.   PHXXAMLIXED

    Great weather, a great audience, and good times.
    Having been twice in Phoenix this month I have to say they have a really great .NET community. Congratulations and thanks for joining us for the training!!

    Here are the decks and the demos.

    Thanks again Phoenix!!   Next stop: Chicago; c u there on friday.


    My guess is that most Americans know this, but I did not.  The picture is from a well known place in Phoenix, called Camelback mountain. 
    Courtesy of Terry Stanley, a training attendee (and now a XAML expert).

  • Jaime Rodriguez

    Programming differences between WPF and SIlverlight, a WHitePaper


    Wintellect just posted a great 70 page white paper on codeplex about the “programming differences between WPF and Silverlight”.  

    I have not dissected it yet, but from a quick scan it looks very useful.
    I will be printing it and dissecting it on my flight to the next (and last) WPF for LOB Tour stop: Chicago.

    Please share feedback on the paper.   Is it useful?? What is it missing?? Is it a fair assessment of the status on our continuum.

  • Jaime Rodriguez

    WPF discussion 090605


    You know the drill: Raw/unedited WPF discussions from inside the mothership.

    Subject: Accessibility tree, and collapsed elements

    We have some UI that we’re collapsing (Visibility=Collapsed). However, even after it’s collapsed, it *seems* to be participating in the accessibility tree (shows up in UIspy). Is this the correct behaviour?

    It seems that this behavior is expected. However UI Elements that are collapsed should have the IsOffScreen property set to true. You could probably filter on that flag.

    Subject: Blur the focus of a window

    With WPF, how can you blur (lose focus) a window?

    There are essentially 3 types of focus, which type do you want to blur?  There are:

    · Logical focus.  This is essentially a way of marking which IInputElement in a given scope should receive keyboard focus if that scope gains keyboard focus.  Within elements that are marked as a focus scope, there will be 0 or 1 logically-focused child elements.  A focus scope is determined by FocusManager.SetIsFocusScope/FocusManager.GetIsFocusScope, and logical focus can be cleared by using FocusManager.SetFocusedElement on the focus scope to null.

    · Keyboard focus.  This is similar to Win32 focus; only one IInputElement on the thread with Win32 focus can be the Keyboard.FocusedElement.  In 3.0/3.5/3.5 SP1, the only way I know of to clear WPF keyboard focus also involves clearing Win32 focus, by calling ::SetFocus(NULL) from user32.  In WPF 4.0 there is a new method coming along, Keyboard.ClearFocus(), which will clear only the WPF keyboard focus.

    · Standard Win32 focus.  WPF keyboard focus is typically kept in-sync with Win32 focus (in that the focused HWND typically contains the Keyboard.FocusedElement), so doing operations which affect HWND focus will generally affect the Keyboard.FocusedElement.


    Of course, you can always make an element lose focus by focusing another element, too.  Calling Keyboard.Focus on some other element should result in PreviewLostKeyboardFocus/LostKeyboardFocus being raised on the element losing keyboard focus.  Similarly, calling FocusManager.SetFocusedElement to some other element in the focus scope should result in PreviewLostFocus/LostFocus being raised on the element losing logical focus.

    Confusingly, perhaps, calling Keyboard.Focus(null) will not clear keyboard focus, but will instead focus the active PresentationSource's root visual.  This can result in Keyboard.Focus(null) actually focusing another element, and not clearing focus.

    Subject: How do I change properties on the Navigation Bar in a WPF Frame?

    I'm working on a page based WPF application, and I want to change the size of the navigation bar in the Frame hosting my pages. I set NavigationUIVisibility="Visible" in order to see the navigation bar, now how do I change properties on the navigation bar like it's size?

    The built-in navigation UI is not directly customizable. You’ll have to replace the entire ControlTemplate of Frame, possibly using the built-in one as a base. This is easy with Blend. Some resources:

    Subject: Scroll issue with hosting a winform within WPF

    I am having an issue trying to scroll a winform control hosted within WPF. I have a view (WPF UserControl) that has 3 elements. A checkbox, a hosted winform control (gray window below) and a combobox.

    Here’s an illustration of this technique for another source: http://blogs.msdn.com/ryanvog/archive/2009/01/20/clipping-legacy-content-hosted-inside-a-wpf-scrolling-region.aspx.

    Subject: RE: Themes\Generic.xaml

    Only resources that are referenced with StaticResource from within the same resource dictionary (i.e. within Generic.xaml) can be strings. For everything else, you must use either a type key ({x:Type Foo}) or a ComponentResourceKey. Styles with no key specified default the key value to the TargetType of the Style.

    Subject: Asynchronous Commands and Dispatcher

    I have a command which executes a long-running operation using BackgroundWorker.  The command exposes a State property to which the UI can be bound to indicate that the operation is in progress or has finished.  The results of the command are bound to a TreeView.  Whenever an element is added to the results, the command does so by calling Dispatcher.BeginInvoke so that the element will be added to the results collection on the UI which causes the TreeView to be updated.  I call the BeginInvoke method with a priority of Background.  Once the command is finished executing, it updates its state to say it’s finished. 

    The problem is that when there are hundreds of elements that have been added to the collection, the UI thread hasn’t finished processing all of those operations that have been queued on the Dispatcher by the time the command says it’s finished.  So the command says it is finished even though the UI thread is still busy processing all the queued operations. 

    One solution is to have the Command update its State property by having the Dispatcher do it via the BeginInvoke call with the same priority.  That would cause the Dispatcher to update the Command’s state once all the other previously added operations have been processed.  But I’m not sure that’s the right approach; it feels very hacky.

    Is there a better way to do this?

    Keep track of the last operation you BeginInvoke over to the UI thread from the worker thread.  When the worker thread is done, before it updates the state property, have it call DispatcherOperation.Wait() to wait for the UI thread to finish.

    Subject: RE: Blocking till message loop empty?

    Nope.  Dispatcher.Invoke, when called on its own thread, will implicitly use Dispatcher.PushFrame.

    Subject: RE: Bounding rectangle for objects on canvas

    GetDescendantBounds returns the bounds without applying any Visual properties like Clip, Transform, Offset, Effect…
    Canvas.Left/Canvas.Top are mapped to Visual.VisualOffset and Visual.VisualTransform. To take the bounding box from what we call “inner coordinate space” (closest to children) to “outer coordinate space” (closest to parent) you have to apply all the transforms, clips, etc. Note that an effect might change your transformation too…

    The easiest way to get the outer bounds is to call on the parent GetDescendantBounds as long as the parent does not have any “vector content” (think ink).  For UIElements you provide “vector content” via OnRender, for DrawingVisual you call RenderOpen, etc. If the parent had any content, it would be included in the descendant bounds. The naming is a little unfortunate since it is not purely “descendant”. We originally had the functionality only consider descendants, but lots of people thought it was what it does now…

    Subject: Disable script debugging for WebBrowser?

    This option exists in the WinForms web browser, is there a way we can access this option in the WPF web browser also? We are having catastrophic issues with modal script debugger popups that make the browser too annoying to be useful.


    Get the native IWebBrowser2 and set the Silent property. See the Community section of the WebBrowser class reference (http://msdn.microsoft.com/en-us/library/system.windows.controls.webbrowser.aspx) for how to get IWebBrowser2.

  • Jaime Rodriguez

    Silverlight3 PlaneProjection Primer


    A while ago, I cracked open Silverlight3’s PlaneProjection (aka 3D perspective transform ) feature. Below you should find the basic intro plus all the advanced stuff that had not been documented when I tried to learn it. It is a long read, if you are already an expert, skip to the “3D scene” section to read the interesting details.

    The post comes with this application that I used to learn and illustrate the points.  Source for the app is here.
    Click on the Figures below to go to the respective page on the demo app. SL3 is required!  You might need to maximize your screen to see the demos. 

    Introducing PlaneProjection
    Silverlight3 introduces a new Projection property on UIElement.   The property is of type Projection (an abstract class).
    In SL3, the only implementation of Projection class is PlaneProjection, which is an implementation of a 3D PerspectiveTransform. As of SL3 beta1, the implementation is software-based (so not hardware accelerated today).
    The UIElement that is projected into this 3D scene is interactive even if projected. Both front and back are interactive.

    PlaneProjection = Transforms + 3D scene

    For me, it is easiest to think of PlaneProjection as a wrapper for a 3D scene and series of 3D Transforms that you can apply to a UIElement to get it to ‘project’ in 3D space.

    The transforms that PlaneProjection applies to its UIElement are: 

    1. A TranslateTransform exposed via LocalOffsetX, LocalOffsetY, LocalOffsetZ in PlaneProjection.
    2. A set of RotateTransform   represented by the CenterOfRotationX, CenterOfRotationY and CenterOfRotationZ  and the RotationX, RotationY an RotationZ properties.
    3. A TranslateTransform(3D), exposed via GlobalOffsetX, GlobalOffsetY, GlobalOffsetZ

    Before I get into these transforms, let’s cover the coordinate system.

    Silverlight 3D coordinate system


    This system is similar to what Silverlight uses in 2D:
    +Y increases as you go down the vertical axis, 
    +X increases as you go to the right.
    +Z increases towards the viewer.

    Note: WPF uses a different system, called Right hand system,  in WPF, the Y increases as you towards the top on the vertical axis. 





                   Figure1. Coordinate System


    A RotateTransform rotates the object around an axis (X,Y,or Z). 
    You specify the CenterOfRotation (which is normalized, 0 to 1, as a percentage of the actual object size) for the axis, and then you specify the angle in degrees for the Rotation.


    imageOn Figure 2, you can see an Image of a duck rotated around the X Axis.  You first see the original, and then four rotations at 40, 80, 120, and 160 degrees. All of the rotations are the same for each row, but the second and third row have a different CenterOfRotationY property.

    The second row has CenterOfRotationY = 0.1; it rotates near the top of the UIElement (10% from the top).  

    The third row has CenterOfRotationY = 0.9;  so it rotates near the bottom of our UIElement.

    While looking at Rotations of 120 and 160 degrees, notice that there is no back material to our object. Silverlight acts as if back was transparent, letting you see the front material but rotated since you are watching from the back.


                                                                                                                                 Figure 2. Rotate Transforms

    You may wonder what happens if I stack two objects in say a Canvas, one on front of the other, like this:                                                                                                                                             

    We have a Red rectangle, right behind a Black one?  What is the back material now if we rotate the Canvas to see the back?
    The back material is still  the Black rectangle; it looks like Silverlight projects what is visible on the screen, so you get the back of the Black rectangle. 

    Rotations can be negative numbers; a rotation of –50 degrees looks like a rotation of 310 degrees; however, if you are animating you will see these animate in opposite directions (and 310 flips a lot more )yet they end up at same spot. 

    For the most part, that takes care of rotate transforms.  The only other thing to notice is that since we are transforming a 2D object on an Axis, the CenterOfRotationY affects RotationX,  and the CenterOfRotationX affects the RotationY.

    Translate Transforms.
    A TranslateTransform simply moves the object by an Offset vector. For example: an object at 1,1,1 with an offset of 50,74,-1 will end up at  51, 75, 0).   The units are Silverlight units relative to the screen; more on this below when we cover the 3D scene.

    PlaneProjection exposes two translate transforms:  A GlobalOffset and a LocalOffset transform:

    GlobalOffset transform
    The GlobalOffset Transform moves the object relative to the screen’s axis. This means the X,Y,and Z offset are in  the coordinate system I showed above in Figure1. Think about it as a translation after the rotation has happened.  The object is rotated first, and then after that, the resulting, rotated object is simply moved or translated.  This model is similar to what we see in 2D space.

    LocalOffset transform
    The LocalOffset as a translate transform applied prior to the rotation.  We already established that the CenterOfRotation affects the rotation.  Consider what happens if we first translate the object and then rotate it around a specific CenterOfRotation,  since the translate transform does *not* change the CenterOfRotation, you end up rotating around the axis with the translation applied.   That is what a LocalOffset transform does.

    Figure 4 on the right shows you what happens with a LocalOffset + Rotation combination applied. 

    imageRow1 shows three images in a spot (marked by red border).  Each image has a different frame (or border) and a different rotation. Green has RotationY=50;  Yellow RotationY=130 (so 180-50).  The third image (black border) has no rotation at all.

    Notice that since first row has not translate transforms, therefore the rotations are in-place (within the red border).

    Row2 shows same images +rotations), but LocalOffsetX=250.   The image in the black frame shows where the image is located after the translation; it is 250 units to the right of the red border (on X axis). Notice that the rotation is not in place any more (not within the red borders). In this row, the center of Origin is 0.5, so the images at 50 and 130 rotations are at symmetrical distance from the center of the red border (which is our center of origin, at 0.5).  

    Row3 has LocalOffsetX=250 and CenterOfOriginX=0.1.
    Since 0.1 is < 0.5, our CenterOfRotation is to the left from the one on previous row; since the center of rotation is farther away from the actual image, our rotation is the widest here.  The yellow frame is furthest from the red border.  
                                                                                                                              Figure 4. LocalOffset Transforms

    The fourth rotation has CenterOfOrigin=0.9, so this time we are moving our CenterOfOrigin closer to where the image was translated to, so our rotation is less wide than it was at both 0.5 and 0.1 . 


    That should cover the transforms!   If you need to play more with this, try the sandbox from the demos page.

    Now we get to the other half of PlaneProjection: a 3D scene. 

    The 3D scene
    A 3D scene usually consists of a Camera,  Lights, a mesh (the shape of your object) and a material (used to “paint” or “cover” your object ).  You need to know the Position of the camera (relative to the objects in the scene) and the FieldOfview angle.


    Figure 5 shows the basic elements of a 3D camera placement. 
    F == field of View (in degrees or radians)
    D == distance (on Z plane) from the camera to the XY plane
    H == ActualHeight of object in our XY plane




                                                                                                                                              Figure 5.  Basic 3D scene

    Those are the basics of a 3D scene, let’s now cover the Silverlight 3 specifics: 

    FieldOfView == 57.0  degrees
    At first, I was slightly concerned that I could not change field of view, but then I noticed that Silverlight does  not clip the 3D scene.  PlaneProjection works similar to RenderTransform where as you scale your UIElement, you can go over the UIElement’s render bounds (ActualHeight/ActualWidth) and the transform does not affect layout.  This means if your container does not clip, then field of view is irrelevant as you are seeing everything regardless.    

    Figure 6 shows Field Of view and clipping interaction 

    Row1: A Canvas with two rectangles inside it. The blue rectangles take half the canvas space and the red rectangle takes 1/3 of the Canvas space.

    Row2: With a PlaneProjection with GlobalOffsetZ= 500,  the Canvas is a twice its original size. Notice there is no clipping.  This is default SL3 behavior, so field of view is fairly irrelevant as you are seeing the whole scene most of the time.

    Row 3: Same PlaneProjection applied to original Canvas, but this time the border hosting the original Canvas is clipping at 300x120..  So you only see partial scene.   Again this is not default behavior but for those wanting to clip, you know it can be done. 



                                                                                                                                     Figure 6. GlobalOffsetZ = 500, 2x.


    D = 999

    The next thing on the scene is the distance from camera to xy plane.  The answer there is a weird 999. The number I am certain, the behavior I am still trying to grasp .  Let’s explain:


    If D was distance to camera and it was 999, then  when you did a GlobalOffsetZ > 999, the object should  not be in the scene, but what SL 3D does is allow for Zindex to be > 999 and then it rotates (as if you were looking at the back I assume).

    Figure 7 shows:
    Row 1: Original object. Rectangle with a gradient. This is very small on purpose (since it is scaled a lot when we increase ZIndex).  

    Row 2: Same object, but GlobalZIndex = 900.  [so 99 away from 999].
    Still looking at the front of the rectangel.

    Row 3: Same object, GlobalZindex = 1098 [so 99 over 999]. Notice that the we are looking at the back of the object.  It is the same size than 900.

    Row 4:  Has two objects. 
    First object = original + GlobalZIndex = 1899 (900 over 999), notice we are looking at the back of object but it is not scaled much. Second object  is Original object + GlobalZIndex = 99. It is same size as GlobalZIndex = 1899 and we are looking at the front.    
                                                                                                                                  Figure 7. GlobalZIndex > 999 

    If you are wondering why when you look at the API for PlaneProjection the default value for GlobalOffsetZ and LocalOffsetZ is 0 and I am saying the camera is at 999,   PlaneProjection applies the D = 999 is by moving the object before you get the scene, so the distance to the camera is there, but you don’t see it (or can’t change it) from the API.

    What about H? why does it matter?
    H is relevant because it tells you where the camera is in relation to the XY plane.  Not the distance to it, but where within that plane the camera is located. The short answer is that the camera is at the center. The long answer is that there is some scaling going on to make that happen. 

    For sizing of our scene, the math would go along H = 2*D*tan (F/2); since both F(57) and D (999) are fixed, then H should also be fixed (1084), but of course our UIElement is not of that same size, so the object is  scaled and aspect ratio is maintained.

    For the most part, you do not notice this scaling (nor should you care), but if needed you can use this knowledge to accomplish two things:

    1. Position the camera
    2. Create a 3D scene where multiple objects of different sizes appear to be in the same scene, with a common camera angle.



    Figure 8.
    Let’s go back to our earlier example where I showed you a clipped scene,  this time the canvas in the last row is 500x120 instead of 300x120. if you see it before changing GlobalOffSetZ, visually it all looks the same. 

    When you animate GlobalOffsetZ, you notice the center of origin of the Projection is farther to the right ( at 250, which is the first third in the rectangle, so our rectangle would no longer clip, part of it is visible. 

    [I removed the clip on the border so you could see the scene, but it is easy to see that some of the red rectangle is still fitting in the border that was clipping the whole rectangle earlier.


                                                                                                                                               Figure 8 – Canvas to position camera.


    The example above is not that exciting or enlightening; you can accomplish some thing similar with a few transforms, so I am not proposing that you change the size of your containers to manipulate the camera, however the trick does come in handy when you have UIElements that are of different sizes but need to “integrate” into a 3D scene; and the UIElements need to be rotated separately.  If you are familiar with WPF, this would be like having multiple GeometryModels within a scene; you rotate these independently, but relative to a single camera and lights scene.

    Since I explained earlier that camera is located relative to the “center” of each UIElement, there fore getting multiple objects of different sizes to have the camera in the exact same spot is not doable unless we workaround it, and the workaround is to apply a Canvas to wrap each of my UIElements, and size all wrapper canvases to the same size, this way as I rotate them and manipulate them, they all have same relative CenterOfOrigin.

    imageFigure 9 demonstrates this trick.    
    Row1 shows a canvas with rectangles in it. The rectangles have slightly different sizes.

    Row2 shows the rectangles translated to GlobalOffsetZ = 500 (twice original size).
    Notice that the “top” of the rectangles are not aligned (unless the height of the rectangle was the exact same prior to the transform). I used the redlines to demonstrate the differences after translation.

    Row 3 translated the canvas instead of the rectangles, notice the top of the rectangles are aligned.

                                                                                                  Figure 9. Using same size Canvas to align UIElements
    to get same Center of Origin.

    OK that covers most of what I found out on Silverlight’s PlaneProjection. I do have a useful sandbox page for playing around with a lot of these concepts.


    On the overall 3D API, I think it is quite simple, yet it lets you do a lot.    

  • Jaime Rodriguez

    Thanks New York. Here is the content.


    The third stop in the “Windows Presentation Foundation for Line Of Business Tour” NYXamlized was  New York City, last Friday and Sat.

    We had a great  crowd, mixed with WPF newbees and experts; this drove us to long training days with lots of questions on both sides of the spectrum. 

    Thanks to the attendees for sticking it out!

    The decks are here.  The demos are here.

    Our last two stops are coming up quickly:
    Phoenix (this weekend) and Chicago (next week).

    Thanks again, New York ( and Philadelphia, and Boston, and New Jersey and any one else who came from out of town).

Page 1 of 1 (8 items)