Tuesday, March 31, 2009

ActualWidth,ActualHeight returning ZERO

In the development of Silverlight it happens often that you don't assign any value to Width and Height of UI Elements in your code,then in run time those values will be referenced.

In that case ActualWidth and ActualHeight must be something you refer to.But if you write code like below,an unpredictable incident may happen to you.


public Page()
{
InitializeComponent();

//Set the location of the button around the corner of the canvas.
Canvas.SetTop(imageButton, 5);
Canvas.SetLeft(imageButton, LayoutRoot.ActualWidth - 25);
}
In the code above ActualWidth of the root canvas is referenced to put the button near the corner of the canvas.But the code fails to get the anticipated value.Actually it returns zero value.So I moved the lines to Loaded event handler,but it didn't make any difference.

At first, I was quite at a loss what should I do.But I went back to basics and referenced documents again,I found the solution.

Value of ActualWidth and ActualHeight are given after layout calculation process has completed.And the process is executed asyncronously ,which means the calculation process is registered in queue of the related thread at the moment when changes have been made to the UI elements.

Then after all lines in a current block executed,the calculation process will begin.

So What to do is to put "referencing ActualWidth and ActualHeight" also in the same queue,which means you should write code like this.


public Page()
{
InitializeComponent();

Dispatcher.BeginInvoke(
() =>
{
Canvas.SetTop(imageButton, 5);
Canvas.SetLeft(imageButton, LayoutRoot.ActualWidth - 25);
}
);


}
BeginInvoke method in Dispatcher in Silverlight API doesn't have paremeter to designate priority.So I think the order you add delgates determines the order of execution, which turns out "Referencing ActualWidth" always comes after layout calculation process in the code above.

I just wanted to make sure my assumption about order of execution,I wrote and run the code below several times.


Dispatcher.BeginInvoke(
() =>
{
Debug.WriteLine("1");
}
);

Dispatcher.BeginInvoke(
() =>
{
Debug.WriteLine("2");
}
);

Dispatcher.BeginInvoke(
() =>
{
Debug.WriteLine("3");
}
);
Numbers were displayed in order "123" all the time,that was what I had anticipated.

I am not a native english speaker,so if my explanation is not good enough for you to understand, Plaese let me know ,I will be grateful.

1 comment:

  1. I wish that embedded Silverlight had this solution.

    Excellent job for non-native English! Just a few comments on that: There is always a space after a period. (Example: Sentence 1. Sentence 2.) No space before the comma, and always a space after (Example: Hello, pleased to meet you!) "Plaese" is spelled "Please".

    ReplyDelete