Get ActualWidth and ActualHeight in Silverlight

October 17, 2008 07:27 by wjchristenson2

You may often encounter situations where you need to acquire the size of a Silverlight object and the Width, Height, ActualWidth, ActualHeight property values are not set.  This can occur if the Width & Height are set to Auto, if the object being referenced is in the process of being added dynamically, or it can occur in a myriad of other circumstances.

Let's assume that we have a Canvas object as our root element for our Silverlight application.  It's Width and Height are set to Auto.  As its parent is resized, the Canvas object will grow & shrink accordingly.  Now if we want to acquire the Canvas size to do some placement logic of Canvas child elements, we run into our problem.

My first approach was to investigate why ActualWidth and ActualHeight were not telling me (the developer) the ... uh... actual width and actual height.  You'd think the property names would say it all, but they don't.  They actually "get or set the rendered width/height of a FrameworkElement."  Ok, that's easy enough.  We'll just wait until the objects are rendered before we position them.  So, I figured I'd hook into my Silverlight's Loaded event.  At this point all objects should be "loaded" and I can acquire the actual size of my Canvas.  Wrong!  ActualWidth and ActualHeight are calculated based on the Width/Height property values and the layout system.  There is no guarantee as to when these values will be "calculated".  So I've found 2 ways to workaround this issue.

Dispatcher.BeginInvoke()
This approach executes a specified delegate asynchronously on the thread the Dispatcher is associated with.  Measurement and layout passes run in Silverlight asynchronously.  Therefore our ActualWidth and ActualHeight object properties can be set AFTER we actually need them.  Using BeginInvoke() ensures that our ActualWidth and ActualHeight calculations are done as we programmatically access them.  Here is a sample use of .BeginInvoke() and the delegate.

'ActualWidth and ActualHeight are calculated values and may not be set yet
'therefore, execute GetLayoutRootActualSize() asynchronously on the thread the Dispatcher is associated with
Me.Dispatcher.BeginInvoke(AddressOf GetLayoutRootActualSize)

Private Sub GetLayoutRootActualSize()
    Me.tbxInvoke.Text = Me.LayoutRoot.ActualWidth.ToString() & ", " & Me.LayoutRoot.ActualHeight.ToString()
End Sub

_SizeChanged Event
My preferred method of accessing ActualWidth and ActualHeight in these situations is by hooking into the FrameworkElement's SizeChanged event.  This event is fired when the ActualWidth and ActualHeight values change for a FrameworkElement.  So let's say we have an element which we need to position based on the size of it's parent.  We can hook into the parent's SizeChanged event and position the child element on the fly.  The ActualWidth and ActualHeight properties of the parent would be present at this time.  Here is a snipped of SizeChanged event handling.

Private Sub LayoutRoot_SizeChanged(ByVal sender As Object, ByVal e As System.Windows.SizeChangedEventArgs) Handles LayoutRoot.SizeChanged
    Me.tbxSizeChanged.Text = Me.LayoutRoot.ActualWidth.ToString() & ", " & Me.LayoutRoot.ActualHeight.ToString()
End Sub

I've uploaded an example using my 3 tests (page Loaded, BeginInvoke(), and _SizeChanged).  Hope it helps!


ActualWidthHeight_Soln.zip (586.38 kb)

Bookmark and Share

Microsoft Releases Silverlight 2

October 14, 2008 01:25 by wjchristenson2

Microsoft has released Silverlight 2 today.  Here are the downloads that I found useful:

Silverlight Tools for Visual Studio 2008 SP1
This allows you to develop Silverlight 2 applications within Visual Studio 2008 SP1.  Make sure you have SP1 installed first on Visual Studio before you attempt to install the tools.

Expression Blend 2 Service Pack 1
The service pack will allow you to develop Silverlight 2 with Expression Blend 2.

Microsoft® Silverlight™ 2 SDK
The Silverlight Tools for VS 2008 SP1 already includes the SL2 SDK.  However, if you are not installing that, you can install this SDK seperately.  The software development kit provides documentation, libraries and tools for developing Silverlight 2 applications.

Microsoft Releases Silverlight 2, Already Reaching One in Four Consumers Worldwide
This is the official press announcement.

I have not found any differences yet between SL2 and SL2RC0.  I'll post if I find any.

Bookmark and Share

Silverlight 2 RC0 is now Available

September 30, 2008 03:52 by wjchristenson2

About the Release
Silverlight 2 Release Candidate 0 is intended for developers so that they can update their existing SL2 Beta applications to work with SL2.  It is important to upgrade your development environment to SL2RC0 so that your SL application will work the day SL2 is officially released.  Some highlights that I found interesting in this new version is 3 new controls: ComboBox, ProgressBar, and the PasswordBox.  There's also some new control skins available.  Scott Guthrie has a nice overview of the new features and gives a great overview of SL2RC0 here.  It also looks like we can now inherit directly from DependencyObject again!  We can also set default values for custom dependency properties using PropertyMetadata.

What should I do?
As a developer, you'll want to download and install the updates. 

Here are the important downloads:

  • Microsoft Silverlight Tools for Visual Studio 2008 SP1
    This will install the necessary Visual Studio updates, Silverlight project templates, RC0 developer runtime, and SDK.
  • Microsoft Expression Blend 2 Service Pack 1 Preview
    This version of Expression Blend is targeted to work with the RC0 developer runtime for Silverlight.
  • Before you begin, ensure you have Visual Studio 2008 SP1 installed.  If you already had the Expression Blend 2 June Preview installed, you'll need to uninstall it first.  Second, install the new Tools for VS 2008 SP1.  Finally, install the MS Expression Blend 2 SP1 Preview.

    After you have installed the updates, you'll want to open your SL application and test/debug/update it to work with the new SL2RC0 version.  You will NOT want to deploy it.  This version is intended for developers only.

    Issues I Ran Into
    The strangest issue I had was a weird bug when I tried to compile my SL application.  "The 'ValidateXaml' task failed unexpectedly."  I found several articles on this error, however simply cleaning the solution and rebuilding it resolved the issue.  The main issue I ran into was the fact that I didn't initially see the Expression Blend update.  Therefore I couldn't use Expression Blend from within VS.  That was a I-D-1-0-T error on my part.

    Bookmark and Share

    Set Dependency Property's Default Value in Silverlight

    September 29, 2008 02:03 by wjchristenson2

    If you are familiar with WPF, you may be used to setting a dependency property's default value through its property metadata.  Unfortunately SL2B2 (Silverlight 2 Beta 2) does not support specifying the default value via the metadata.  This was shocking to me as coders often need to check to see if a property has been set or not.  So what value is returned if the property is not set?  According to this article, it depends on the data type.  Reference-type dependency properties will be null, value-types are the default constructed value (double = 0.0), strings will be an empty string.

    So I figured I could use the Nullable(Of T) generic structure as the data type of my dependency property to get around this limitation.  Doing this would allow me to test to see if the dependency property has been set or not by simply coding something like this: PropertyName.HasValue.  This works great programmatically, but I soon found that setting the dependency properties via XAML caused parser exceptions.  I also lost my intellisense when coding in XAML.  I've posted on the MS Silverlight forums to get an answer why Nullable(Of T) generic structures' XAML are unable to be parsed.  "Unfortunately XAML doesn't support Nullable types because they're generic types".

    So here's my solution.  We found that we cannot use property metadata to set default values and we found that Nullable(Of T) generic data type structures for dependency properties do not play well with XAML.  Instead I just set my dependency property values when the object is constructed.

    Partial Public Class SilverlightControl1
        Inherits UserControl
    
        Public Shared ReadOnly ColorProperty As DependencyProperty = DependencyProperty.Register("Color", GetType(Color), GetType(SilverlightControl1), Nothing)
    
        Public Property Color() As Color
            Get
                Return CType(GetValue(SilverlightControl1.ColorProperty), Color)
            End Get
            Set(ByVal value As Color)
                SetValue(SilverlightControl1.ColorProperty, value)
            End Set
        End Property
    
        Public Sub New()
            InitializeComponent()
    
            'set dependency property default value
            Me.Color = Colors.Transparent
        End Sub
    End Class

    ** Edit 9/30/2008 **
    SL2RC0 (Silverlight 2 Release Candidate 2) now allows programmers to set a custom depencency property's default value! Simply construct a new PropertyMetadata object and pass in the default value.

    Bookmark and Share

    How to Make a Dashed Line in Silverlight

    September 8, 2008 09:22 by wjchristenson2

    I attempted to create a dashed line today in Silverlight and quickly found myself searching for examples on how to do so.  In ASP.NET I'm used to setting a BorderStyle property to do so.  With Silverlight, we have to do a little more work.  I will show how you can create a dashed line in Silverlight via XAML and I will also show you how to do this programmatically.  This is what our final Silverlight application will look like once we are finished.

    "StrokeDashArray" is the property which we use to define our dashes.  This property indicates the pattern of dashes and spaces between the dashes.  The first value is the width of the dash and the second value is the space between the dashes.

    <Line x:Name="Line1" X1="20" Y1="10" X2="300" Y2="10" Stroke="#4284B0" Canvas.Top="10" StrokeDashArray="4 2"/>

    This is how you would define a dashed line in XAML.  Here we have a line where each dash is 4 pixels wide and has a 2 pixel spacer between each dash.  Next, I will show you how you can create a dashed line programmatically.

    Private Sub Page_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
        Dim dashArray As DoubleCollection = New DoubleCollection()
        With dashArray
            .Add(10.0)   'width
            .Add(5.0)   'space
        End With
    
        Me.Line2.StrokeDashArray = dashArray
    End Sub

    Here we define our dashed line programmatically.  You see that I create a dashArray object first of a DoubleCollection type.  I fill it with a 10 and a 5 (10 pixel wide dash with 5 pixel spacers in between each dash).  I then assign my line's StrokeDashArray property to my dashArray DoubleCollection.

    SilverlightDashedLine_Soln.zip (537.26 kb)

    Bookmark and Share