Page view counter

Silverlight Tips of the Day - Blog by Mike Snow

Game Programming with Silverlight

Silverlight Tip of the Day #13 - How to Get an Images Dimensions in Silverlight.

Since Silverlight is based upon an asynchronized model, getting an image width and height immediately after loading it is not possible. However, you can monitor its download progress and obtain the image dimensions once the progress has reached 100%.

Below is a sample that demonstrates how to do this. Few important notes:

  • BitmapImage requires the namespace System.Windows.Media.Imaging;
  • ActualWidth and ActualHeight are calculated values. The calculation happens after a layout pass. Therefore, the image must be in the tree in order for hits size to be accounted for. Thus my call to GameCanvas.Children.Add(grass);
  • The image you are adding to your canvas must be first added to your Silverlight application project in Visual Studio. Make certain your path to this image is correct.
  • The call to Dispatcher.BeginInvoke(delegate() { … } ); is required before you obtain the Width/Height or they might be intermittently zero.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
 
namespace SilverlightApplication12
{
    
    public partial class Page : UserControl
    {
        private Image grass;
 
        public Page()
        {
            InitializeComponent();
            LoadImage("grass.png");
        }
 
        private void LoadImage(string path)
        {
            Uri uri = new Uri(path, UriKind.Relative);
            BitmapImage bitmapImage = new BitmapImage();
            bitmapImage.UriSource = uri;
            bitmapImage.DownloadProgress += 
                new EventHandler<DownloadProgressEventArgs>(bitmapImage_DownloadProgress);
            
            grass = new Image();
            grass.Source = bitmapImage;
            GameCanvas.Children.Add(grass);
        }
 
        void bitmapImage_DownloadProgress(object sender, DownloadProgressEventArgs e)
        {
            if (e.Progress == 100)
            {
                Dispatcher.BeginInvoke(delegate()
                {
                   double height = grass.ActualHeight;
                   double width = grass.ActualWidth;
                });
            }
        }
    }
}

Page.xaml:

<UserControl x:Class="SilverlightApplication12.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <ContentControl x:Name="MyContent">
            <Canvas x:Name="GameCanvas" ></Canvas>
        </ContentControl>                              
    </Grid>
</UserControl>

Thank you,
--Mike Snow

 Subscribe in a reader

Comments

robhouweling said:

Hi Mike,

Thanks for this. I do have a question however. What if I have a situation where I have no knowledge about the images that are going to be loaded (retrieved from a webservice or something).

In your example you create a private field grass which you add to the canvas in the loaded event. This won't be possible in my situation.

Why is the image object returning the width and height when placed on the Canvas. I can see no logical reason for this behavior. I do understand the async issue, but it should be possible to read the width and height of an image once the bitmap is loaded and set as the imagesource.

Kind regards,

Rob Houweling

# July 1, 2008 3:40 AM

Silverlight news for July 1, 2008 said:

Pingback from  Silverlight news for July 1, 2008

# July 1, 2008 5:01 AM

mike.snow said:

Hey Rob, when you retreive an image from a web server you will be creating the image locally correct? At this time you add theDownloadProgress event and then get its size. I might, however, be reading your question wrong. If you send me some sample code (msnow@microsoft.com) I can take a look for you.

As for your second question, until the image is actually added to the canvas it's not really loaded. I believe this is done to save memory and for better resource management.

# July 1, 2008 2:02 PM

Visual Web Developer Team Blog said:

Interested in learning something new about Silverlight almost every day? I will be posting “Tips of the

# July 1, 2008 6:44 PM

Community Blogs said:

16 posts today... yikes: Corrina Barber on Sparkling Client, Training CD update via Tim Heuer, Progressive

# July 2, 2008 2:29 AM

14 Silverlight Tips | DavideZordan.net said:

Pingback from  14 Silverlight Tips | DavideZordan.net

# July 2, 2008 4:31 AM

Guillaume Andre said:

If you are in a Canvas you can also use SizeChanged event.

# July 8, 2008 3:26 AM

RajeevGoel said:

Mike,

Great Tip of the Day.  I've been trying to figure out how to do this for a while now.  

Is it okay with you if I post this and other samples from your blog onto http://silverlightnuggets.com?

Thanks,

Rajeev

rgoel@silverlightnuggets.com

# July 11, 2008 1:40 PM

mike.snow said:

Rajeev- Yes, you may post. I added a link to your site from my "Silverlight Resources" section. Your site is great!

# July 11, 2008 2:21 PM

Just code - Tamir Khason said:

If you’ll try to use ActualWidth and ActualHight of controls with explicitly set Width and Height, you

# July 12, 2008 4:21 AM

Just Code - Tamir Khason said:

If you’ll try to use ActualWidth and ActualHight of controls with explicitly set Width and Height, you

# July 12, 2008 4:22 AM

???????????????????????????? ???????? ?????????????????? ???????????????? ???????? - ?????????? - ???????????? ????.???? said:

Pingback from  ???????????????????????????? ???????? ?????????????????? ???????????????? ???????? - ?????????? - ???????????? ????.????

# August 4, 2008 11:20 PM

WzBn said:

Hi, thanks for the data, but I'm try to useit in the way below, but the event  it is not fired.

Do you have any suggestion?

Thnaks in advance

 Private Sub UpdateBackground(ByVal mmImg As System.IO.MemoryStream)

   Try

     Dim Img As New BitmapImage

     Img.SetSource(mmImg)

     Dim imbck As New Image

     AddHandler Img.DownloadProgress, AddressOf BckgDonloadProgress

     With imbck

       .Source = Img

       .HorizontalAlignment = HorizontalAlignment.Left

       .VerticalAlignment = VerticalAlignment.Top

       .Stretch = Stretch.None

     End With

     ThisPage.MainArea.Children.Add(imbck)

   Catch ex As Exception

     ThisPage.ShowError(ex)

   End Try

 End Sub

Public Sub BckgDonloadProgress(ByVal sender As Object, ByVal e As DownloadProgressEventArgs)

   Try

     If e.Progress = 1 Then

     Dim Wd, Hg As Double

     Wd = CDbl(CType(sender, BitmapImage).GetValue(Canvas.HeightProperty))

     Hg = CDbl(CType(sender, BitmapImage).GetValue(Canvas.WidthProperty))

     If ScreenCollection(CurrentScreen).Width < Wd Then ScreenCollection(CurrentScreen).Width = Wd

     If ScreenCollection(CurrentScreen).Height < Hg Then ScreenCollection(CurrentScreen).Height = Hg

end if

   Catch ex As Exception

     ThisPage.ShowError(ex)

   End Try

 End Sub

# November 3, 2008 10:33 AM

mike.snow said:

Hard to say looking at your code. If you zip up a sample project, email it to msnow at microsoft.com I will take a quick look at it for you.

Thanks,

--Mike

# November 3, 2008 1:04 PM

Quick Silverlight tip: Why my ActualWidth and ActualHeight equal 0? | Tamir Khason - Just code said:

Pingback from  Quick Silverlight tip: Why my ActualWidth and ActualHeight equal 0? | Tamir Khason - Just code

# January 1, 2009 3:54 AM

Silverlight Tips of the Day - Blog by Mike Snow said:

The purpose of this post is to create an outline summary all the blogs from my Silverlight tips of the

# January 2, 2009 5:56 PM

o UAU nosso de cada dia said:

essa lista eu copiei desse blog bárbaro (acompanhe por RSS você também): uma lista de dicas super úteis

# January 3, 2009 6:25 AM