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.

Privacy Policy

If you require any more information or have any questions about our privacy policy, please feel free to contact us by email at mykonos2008@hotmail.co.jp.


At eklabjapan.blogspot.com/, the privacy of our visitors is of extreme importance to us. This privacy policy document outlines the types of personal information is received and collected by eklabjapan.blogspot.com/ and how it is used.

Log Files
Like many other Web sites, eklabjapan.blogspot.com/ makes use of log files. The information inside the log files includes internet protocol ( IP ) addresses, type of browser, Internet Service Provider ( ISP ), date/time stamp, referring/exit pages, and number of clicks to analyze trends, administer the site, track user’s movement around the site, and gather demographic information. IP addresses, and other such information are not linked to any information that is personally identifiable.


Cookies and Web Beacons
eklabjapan.blogspot.com/ does use cookies to store information about visitors preferences, record user-specific information on which pages the user access or visit, customize Web page content based on visitors browser type or other information that the visitor sends via their browser.


DoubleClick DART Cookie


.:: Google, as a third party vendor, uses cookies to serve ads on your site.

.:: Google's use of the DART cookie enables it to serve ads to your users based on their visit to your sites and other sites on the Internet.

.:: Users may opt out of the use of the DART cookie by visiting the Google ad and content network privacy policy at the following URL - http://www.google.com/privacy_ads.html


Some of our advertising partners may use cookies and web beacons on our site. Our advertising partners include .......
Google Adsense


These third-party ad servers or ad networks use technology to the advertisements and links that appear on eklabjapan.blogspot.com/ send directly to your browsers. They automatically receive your IP address when this occurs. Other technologies ( such as cookies, JavaScript, or Web Beacons ) may also be used by the third-party ad networks to measure the effectiveness of their advertisements and / or to personalize the advertising content that you see.


eklabjapan.blogspot.com/ has no access to or control over these cookies that are used by third-party advertisers.


You should consult the respective privacy policies of these third-party ad servers for more detailed information on their practices as well as for instructions about how to opt-out of certain practices. eklabjapan.blogspot.com/'s privacy policy does not apply to, and we cannot control the activities of, such other advertisers or web sites.


If you wish to disable cookies, you may do so through your individual browser options. More detailed information about cookie management with specific web browsers can be found at the browsers' respective websites.

Monday, March 30, 2009

Making a Silverlight app getting data from Google app Engine


Recently I am interested in Silverlight2 and Google App Engine.
So I've made a simple Silvelight2 app getting data from a mod on Google App Engine.

I adopted REST Protocol in communication between Silverlight2 and App Engine.

Here is the Server-Side code written in Python,about which you don't have any other choice.


#!-*- coding:utf-8 -*-
from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app

class MainPage(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/xml'
self.response.out.write('<?xml version="1.0" encoding="UTF-8" ?>')
self.response.out.write('<Person>')
self.response.out.write('<LastName>Jackson</LastName>')
self.response.out.write('<FirstName>Michael</FirstName>')
self.response.out.write('</Person>')

application = webapp.WSGIApplication(
[('/', MainPage)],
debug=True)

def main():
run_wsgi_app(application)

if __name__ == "__main__":
main()

The code above simply returns XML format string.

XML Format:


<?xml version="1.0" encoding="UTF-8" ?>
<Person>
<LastName>Jackson</LastName>
<FirstName>Michael</FirstName>
</Person>
Next is the Client-Side code.

Silverlight2 has XML Serialize API. With it you can Deserialize XML String to a C# Class insntance.

So I defined Person class in first that corresponds to the XML format.

Person.cs:

public class Person
{
public String LastName { get; set; }
public String FirstName { get; set; }
}
The following code makes an Asynchronous http request.
WebRequest class in Silverlight doesn't have GetResponse() which is synchronous version of BeginGetResponse() existing in .NET Framework.


private String _svrUrl = "http://localhost:8080/";

private void OnLoaded(Object sender, RoutedEventArgs e)
{
try
{
WebRequest req = WebRequest.Create(new Uri(_svrUrl));
req.Method = "GET";

req.BeginGetResponse(new AsyncCallback(GetResponseCallback), req);
}
catch { }
}
The callback method is called when the server return a response,
then I start reading data from the response stream asynchronously using ThreadPool class.


private void GetResponseCallback(IAsyncResult ar)
{
try
{
WebRequest req = ar.AsyncState as WebRequest;
WebResponse res = req.EndGetResponse(ar);

Stream stream = res.GetResponseStream();

ThreadPool.QueueUserWorkItem(new WaitCallback(ReadContents), stream);
}
catch { }
}
In the last part,we deserialize the person class instance from the XML Stirng read from stream.

Be sure to use Dispather accessing to a control in a code block executed by a diffrent thread.


private void ReadContents(Object stream)
{
Person person = null;

using (StreamReader reader = new StreamReader(stream as Stream))
{
XmlSerializer serializer = new XmlSerializer(typeof(Person));

person = serializer.Deserialize(reader) as Person;

}

Dispatcher.BeginInvoke(
() => {
_lastName.Text = person.LastName;
_firstName.Text = person.FirstName;
}
);
}