May 2007 - Posts

Microsoft surface
Wed, May 30 2007 17:10

wow!

by luisabreu | with no comments
Filed under:
Cool post on using WCF and NHibernate
Wed, May 30 2007 9:45

Great piece of work which you can read here.

by luisabreu | with no comments
Filed under:
Siverlight: loading XAML files
Tue, May 29 2007 22:42

Currently, we're limited in the ways we can open XAML files. Even though there's a File API on the mini-CLR platform that is used by Silverlight alpha, most of its methods are marked as SafeCritical, which means you can't just call them from your code. This isn't really a big issue if we're talking about files you control. In these cases, you can embed  the file on your dll and then load it at runtime. For instance, if you're following the control approach (which is used by some of the Silverlight samples), then you'll be doing something like this (writing it here so that you don't need to go to the site to look at it):

Stream xamlStream = this.GetType().Assembly.GetManifestResourceStream( complete_resource_name_goes_here);
rootReference = this.InitializeFromXaml( new StreamReader( xamlStream ).ReadToEnd() ) as Canvas;

Ok, that's cool, but what happens when you need to load xaml and add it to an existing canvas? In that case, you need to get the xaml in text format and pass it to the Load method of the XamlReader class. Reusing the previous example, you'll end up with something that looks like this:

Stream xamlStream = this.GetType().Assembly.GetManifestResourceStream( complete_resource_name_goes_here);
string xaml = new StreamReader( xamlStream ).ReadToEnd();
Canvas aux = (Canvas)XamlReader.Load( xaml );

And that's all there is to it.

by luisabreu | with no comments
Filed under:
Submiting a form from a silverlight page
Tue, May 29 2007 15:23

If you're using Silverlight 1.1 alpha, you might need to submit a form from your silvelright page's codebehind file. You can do this easily by calling the static method Submit exposed by the HtmlPage class. It's as simple as doing this:

HtmlPage.Submit();

There's also an override which lets you specify the name of the form you want to submit. Unfortunately, if you're integrating Silverlight on an ASP.NET page, you might face some problems which you might not expect. For starterts, you'll get an empty __EVENTTARGET value in your postback. Your first attempt might be to handle the onsubmit event from javascript and fill the value of that hidden field. Unfortunately, I believe that the Silverlight control will submit your page by calling the IHTMLFormElement::submit method (or something along those lines). This mean that you won't get notified during the submission of the form (in other words, the onsubmit event won't be fired).

A possible workaround for this is to set the __EVENTTARGET hidden field from your codebehind page. Something like this will work without any problems:

HtmlElement eventTarget= HtmlPage.Document.GetElementByID("__EVENTTARGET");
eventTarget.SetAttribute("value", "bt");
HtmlPage.Submit("form1");

As you might guess, this isn't really production code. In a real app, you'd probably need to send more info or do more things before submitting the form. In those cases, you might, for instance, expose an event which would be handled by Javascript code. You would at least want to receive the ID of the button, which you could do by exposing a scriptable property.

by luisabreu | with no comments
Filed under:
Oleg has relelase Iron XSLT
Mon, May 28 2007 21:32

Looking for some improvement on VS for handling XSLT code? Look no further! Oleg has built a VS plugin that provides better integration with XSLT. And it's free! Go get it here.

by luisabreu | with no comments
Filed under:
Adding ellipsis to your Silverlight TextBlocks
Wed, May 23 2007 23:37

Suppose you have a TextBlock and you need to make sure that its content isn't "cropped". In fact, what you'd like is to have "..." automatically appended to the portion of text that is shown to the user. Here's a method that does that:

private static string GetStringWithEllipsis(TextBlock txt)
{
  double actualWidth = txt.ActualWidth;
  double specWidth = txt.Width;
  if (specWidth> actualWidth)
  {
      return txt.Text;
  }
  TextBlock auxTxt = new TextBlock();
  auxTxt.FontFamily = txt.FontFamily;
  auxTxt.FontSize = txt.FontSize;
  auxTxt.FontWeight = txt.FontWeight;
  auxTxt.Text = "..."

  int i = 0;
  for (; i < txt.Text.Length; i++)
  {
      auxTxt.Text += txt.TextIdea;
      if (auxTxt.ActualWidth >= specWidth)
     {
         break;
      }
  }
  return i < txt.Text.Length ?
      string.Concat(txt.Text.Substring(0, i - 1), "...") : txt.Text;
}

I start by creating a dummy TextBlock that I'm using to copy the chars until its ActualWidth is bigger or equal to the specified width. So, if you have the following TextBlock:

<TextBlock x:Name="txt" Width="100" Height="100"
            Text="Just some info I've typed here" TextWrapping="NoWrap" />

You can simply call:

txt.Text = GetStringWithEllipsis(txt);

from your load event handler and you should be ready to go!

(thanks to Mark Rideout for the hints he gave me in the Silverlight forums)

by luisabreu | 1 comment(s)
Filed under:
Creating a photo album at flickr
Tue, May 22 2007 22:47

yeah, I've finally did it...and the stars are my cats! I'll be uploading more pics in a near future :)

by luisabreu | 2 comment(s)
Filed under:
ASP.NET future bits: the Media server control
Tue, May 22 2007 21:56

I'm just putting this here for the sake of completeness (since I'm trying to run through all the new features added by the future bits). I'm only willing to say that it's based on the new Xaml server (and you know that i'm not happy with the Xaml control, right?)...

by luisabreu | with no comments
Filed under:
Calling your WCF web service from an ASP.NET AJAX page
Tue, May 22 2007 15:44

The 3.5 beta version of the .NET platform lets us use JSON as the serialization format used by a web service call. The best of all is that this means that we can now call a web service from an ASP.NET AJAX page.

To do this, you need to add some entries to your configuration file (on the server side). Getting a proxy on the client side is a simple as adding a service reference through the ScriptManager control. Lets start by seeing the service code (which was generated by adding a new WCF service to an AJAX futures enabled web site):

[ServiceContract()]
public interface ITest
{
    [OperationContract]
    string MyOperation1(string myValue);
}

public class Test : ITest
{
    public string MyOperation1(string myValue)
    {
       return "Hello: " + myValue;
     }
}

The svc file looks like this:

<%@ ServiceHost Language="C#" Debug="true" Service="Test"
              CodeBehind="~/App_Code/Test.cs" %>

Now you need to add an endpoint that is able to understand JSON. In my case, I wanted to expose a mex endpoint too, so I ended up with the following definitions for my web service:

<services>
  <service name="Test" behaviorConfiguration="metadataSupport">
         <endpoint binding="webHttpBinding"
                    behaviorConfiguration="jsonBehavior"
                    contract="ITest"
                    bindingConfiguration="jsonBinding"/>
          <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
   </service>
</services>

As you can see, i'm using  a WebHttpBinding and I'm saying that there's a new jsonBinding element which configures the traditional webHttpBinding that is introduced by default by the WCF framework. In this case, we're just setting the message encoding to JSON:

<bindings>
  <webHttpBinding>
        <binding name="jsonBinding" messageEncoding="Json"/>
  </webHttpBinding>
</bindings>

We also need to add a new behavior that looks like this:

<behaviors>
  <serviceBehaviors>
     <behavior name="metadataSupport">
         <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
     </behavior>
   </serviceBehaviors>
   <endpointBehaviors>
        <behavior name="jsonBehavior">
           <enableWebScript />
        </behavior>
   </endpointBehaviors>
</behaviors>

And that's it! the only thing you need to do to call this WCF service from your AJAX ASP.NET page is add a reference to the web service:

<asp:ScriptManager ID="ScriptManager1" runat="server">
  <Services>
     <asp:ServiceReference Path="Test.svc" />
  </Services>
</asp:ScriptManager>

Doing this ends up inserting the following js code in your page:

Type.registerNamespace('tempuri.org');
ITest=function() {
ITest.initializeBase(this);
this._timeout = 0;
this._userContext = null;
this._succeeded = null;
this._failed = null;
}
ITest.prototype={
MyOperation1:function(myValue,succeededCallback, failedCallback, userContext) {
return this._invoke(ITest.get_path(), 'MyOperation1',false,{myValue:myValue},succeededCallback,failedCallback,userContext); }}
ITest.registerClass('ITest',Sys.Net.WebServiceProxy);
ITest._staticInstance = new ITest();
ITest.set_path = function(value) { ITest._staticInstance._path = value; }
ITest.get_path = function() { return ITest._staticInstance._path; }
ITest.set_timeout = function(value) { ITest._staticInstance._timeout = value; }
ITest.get_timeout = function() { return ITest._staticInstance._timeout; }
ITest.set_defaultUserContext = function(value) { ITest._staticInstance._userContext = value; }
ITest.get_defaultUserContext = function() { return ITest._staticInstance._userContext; }
ITest.set_defaultSucceededCallback = function(value) { ITest._staticInstance._succeeded = value; }
ITest.get_defaultSucceededCallback = function() { return ITest._staticInstance._succeeded; }
ITest.set_defaultFailedCallback = function(value) { ITest._staticInstance._failed = value; }
ITest.get_defaultFailedCallback = function() { return ITest._staticInstance._failed; }
ITest.set_path("/AJAXFuturesEnabledWebSite2/Test.svc");
ITest.MyOperation1= function(myValue,onSuccess,onFailed,userContext) {ITest._staticInstance.MyOperation1(myValue,onSuccess,onFailed,userContext); }

which really looks similar to waht you get when you add JSON support to an ASMX web service.

by luisabreu | 13 comment(s)
Filed under: ,
ASP.NET future bits: the Xaml server control
Mon, May 21 2007 23:13

In one word: needs improvements! If you use this control, you'll be able to insert a Silverlight control in your page. As you might expect, the server control lets you parameterize several of the properties of the Silverlight control. However, it'll generate an object or embedded tag (depends on the browser), which means that you'll get that annoying rectangle with a message box that says that you must click to activate the control. Now, this is really a bad call since injecting javascript from the server on the page is really easy and would completly solve the problem (can anyone explain why hasn't the silvetlight.js file been embedded in the dll so that the render of this control would only generate the div used as a container and inject the traditional createSilverlight method? sometimes, it looks like MS likes to complicate things).

btw, I've done some digging and I've found why MS added this "feature" to IE: guess what? it's because of legal issues related with patents. It's ironic, right?

Dynamic data pages: exposing your data through RSS feeds
Mon, May 21 2007 22:49

The DynamicRssLink control generates a link that you can put in your page and that is responsible for initiating the automatic generation of an RSS feed that you may consume on your blog reader. By default, the control generates an Hyperlink control. Following the same principles explained here, you can customize its appearance (or event create a new Hyperlink control and associate it with the DynamicRssControl).

When you drop a DynamicRssLink control on a page, you'll want to override the GetRssFields method that your page inherits from the DynamicDataPage base class. You're supposed to return (at most) 2 column names that you want to show in your RSS feed. Again, you can follow the approaches presented here. The following example overrides this method and returns a simple column and a dynamic column (again, for the Students table):

public override IEnumerable GetRssFields ()
{
   return new object[] { 
      "StudentID",
       new DynamicDataColumn( "Complete info",
                                                 delegate{ 
                                                      return string.Concat( EvalS( "Name" ), " - ", EvalS( "Address" ) );
                                                   } )
   };
}

If you subscribe the feed, do note that clicking on an item will send you back to the details view page of that table (which takes into account these aspects).

by luisabreu | with no comments
Filed under:
Dynamic data pages: showing different views of your data
Mon, May 21 2007 22:07

As we've seen, by default pages must have the same name as the table from which it gets the data that it presents to the user. And what if you want to supply several views of your data? Or if you don't really want to expose your table? In that case, you must change some of the attributes presented on the <dynamicDataControls> section. In order to illustrate the steps you must follow, lets make some modifications to the example we've been using on this series.

As you might recall, we have a very simple database that only has 2 tables: Students and Contacts. If we add the following to the web.config file:

<dynamicDataControls showAllTables="true" listView="stud" detailsView="stud2">
  <nameMap>
    <add table="students" pathPrefix="~/stud" />
    <add table="contacts" pathPrefix="~/conts" />
   </nameMap>
</dynamicDataControls>

With these entries, we're saying that Student's table info will be found inside the stud directory. On the other hand, contact info should be obtained from the conts folder. If you open your browser and point it to the auto.axd handler I've mentioned here, you'll see that when you try to get info from the students table, you're automatically redirected to the stud directory (getting something like http://localhost:52508/dynamicwebsite/stud/list.aspx). The name list.aspx is important and has special meaning for dynamic data pages applications. By default, it should have code that shows a list of the items presented on your table. Besides the special list.aspx url, there's also the details.aspx. you can customize both of these urls by setting the listView and detailsView attributes on the dynamicDataControls element. For instance, the next example changes these names to lista and detalhes (portuguese for the names used by default):

<dynamicDataControls showAllTables="true" listView="lista" detailsView="detalhes">

As you might expect, you're supposed to have pages inside the previous folders that personalize the DynamicList and DynamicDetails controls used to present info about those tables. It's important to notice that these names are only important when using the automatic navigation features that are provided by the dynamic data controls. Do notice also that you can have more pages inside your folder with different views of your data.

by luisabreu | with no comments
Filed under:
Dave and how to call JS from C#
Mon, May 21 2007 20:57

Dave has a nice post showing how to call JS methods from C#. As I've also said in the past, it's not really complicated, though I still don't like it very much. Why don't I like it? well, simply because it seems like one can't hook up several methods to handle the event (which really sucks!).

I think it might be good to recall that if you call the RegisterScriptableObject, then you must garantee that all the properties exposed by the object that were annotated with the ScriptableAttribute attribute must be of type int, double, string or ScriptableObject. If you don't do this, then you'll end up getting an exception when you register your object.

by luisabreu | with no comments
Filed under:
Sidebar gadget bug list
Sun, May 20 2007 23:00

Jon Abbot has a list with several know bugs (with code that reproduces those problems) here. Very cool resource. Just wish that there was a similar one for silverlight.

by luisabreu | with no comments
Filed under:
Creating a new Storyboard dynamically
Sat, May 19 2007 15:01

In the last day, I've found another quirk with the current 1.1 alpha release of Silverlight. Normally, you create an animation with markup code (ie, XAML). However, I wanted to use C# code and wanted to be able to create a new storyboard dynamically. After reading the docs, I thought that I should be able to call the constructor of each of the items used in the animation and then add it to a Canva's resources collection.

It simply didn't work out that way. The only way I've managed to create the animation dynmically was by loading the XAML dinamically. Since today I've seen this being asked in the forums, I though i should put it here.

Here's some demo code:

<Canvas
xmlns="http://schemas.microsoft.com/client/2007"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="parentCanvas"
Loaded="Page_Loaded"
x:Class="SilverlightTests.Page;assembly=ClientBin/SilverlightTests.dll"
Width="640"
Height="480"
Background="White">
  <Rectangle x:Name="rectangle" Width="100" Height="200" Fill="#FFC13131" />
</Canvas>

And then, on the code behind file:

public void Page_Loaded(object o, EventArgs e)
{
  // Required to initialize variables
  InitializeComponent();

   string xaml = "<Storyboard><ColorAnimationUsingKeyFrames BeginTime=\"00:00:00\"  "    +    
                           "Storyboard.TargetName=\"rectangle\" Storyboard.TargetProperty=\"(Shape.Fill)." +
                          "(SolidColorBrush.Color)\"><SplineColorKeyFrame KeyTime=\"00:00:00\" "+
                          "Value=\"#FF2C0606\"/><SplineColorKeyFrame KeyTime=\"00:00:01\" "+
                          "Value=\"#FFDD4848\"/></ColorAnimationUsingKeyFrames></Storyboard>"

   Storyboard anim = (Storyboard)XamlReader.Load(xaml);
   this.Resources.Add(anim);
    anim.Begin();//run the animation
}

I guess that there are several problems that need to be fixed before the alpha is ready to be used in real projects...

by luisabreu | with no comments
Filed under:
Still about Petzold's book
Sat, May 19 2007 1:24

It seems like Jeff's post's ripples haven't stopped yet. Today, I've read Eric's post on the subject. Even though he's really a smart guy, I think that this time he's wrong. According to his post, Petzold's book will give you a deep understanding of WPF. Well, as I've said before, Pezold is good and there really is some content on his book.

In 2007, i think that it's fair to say that UML class diagrams are a must if you want to show hierarchies. That doesn't happened in Petzold's book. Thorough concise writing is needed in modern technical books. Again, I don't see that in his last book. Finaly,  I can't say how much I agree with Matt's coment:

"(...)

A book can be full of "deep understanding". But you can only gain that understanding if you are actually able to read the book.

I usually agree with you Eric but this is not so much about the technical content as much as it is about the writing style. Petzold's other books were never like this. This one was very poorly written and is a really "yawner" even for those of us who seek deep understanding."

And I still haven't forgotten about Petzold's guesses on how things are implemented internally as if there's no Reflector...

by luisabreu | with no comments
Filed under:
Building my first Silverlight sidebar gadget
Sat, May 19 2007 0:56

well, almost, that is. And what a ride it was, letting me get some important info on several aspects related with C# coding and Javascript interop.

First, I'd like to thank Bruce Williams for providing the answer for the issue related with running Silverlight on my 64 bits machine: the problem is that you can't load the Silverlight gadget on the 64x sidebar.exe. So, if you want to run it, you'll have to kill the default sidebar process and go to the program files(x86) folder and launch the 32 bits version. Sucks, but at least it works.

There are some quirks related with the way the current bits work. In my case, I tried using one of those cool round rectangles for the background but it simply didn't work out. While trying this, I ended up getting a white rectangle for the area of the Silverlight activex control (ie, the clipping I set up on  my canvas was filled with white). I've also tried setting the gadget to windowless (which really is needed, as we'll see next) and set the background attribute of the object passed to the createSilverlight object to the same  color as the top canvas background. It didn't work either. I really didn't had any time left to re-read the docs, so maybe i'm doing something wrong here.

Another important thing: if you're silverlight canvas occupies all the available space of the html page used by the gadget, you 'll want to set its isWindowless property of the anonymous js object passed to the createSilverlight method to true. Not doing this will result in not getting the traditional right side menu that lets you close the gadget, get its settings or drag it around the page.

Another quirk i've found is related with flyouts. In my simple example, I have a flyout that shows a traditional HTML page. This page has a close button which, when clicked, should close the flyout. It seems like the siverlight control "eats"the focus and clicking on that button doesn't do anything. In fact, in order for the button to get the click, I need to press the TAB key. After doing this, the flyout looses its grayed appearance (btw, I've only noticed that is as little grayed out after pressing the TAB key) and after that, it responds correctly to clicks and key presses. I need to investigate this a little more to see what's really going on there.

The WORST problem i've faced is related with  cross-domain calls and the BrowserHttpWebRequest class. I know I've mentioned it here, but i must really do it again. You cannot make cross-domain calls with this object. By now, some of you must be thinking: "you're really stupid. cross-domain calls are disabled and since the class is a light wrapper around the XMLHttpRequest object (well, i didn't had the time to check this, but if you look at my previous post, you'll see that there's a link that seems to confirm this), you really shouldn't get away with it". Most of this is true (though there are some things you can do to make cross-domain calls possible in some scenarios).

However, it's a completly different story when you're building gadgets. In those cases, cross-domain calls are indeed allowed (in fact, most sidebar gadgets use these kind of calls!). Unfortunately, the public constructor of the BrowserHttpWebRequest class always sets the value of the enableCrossDomainCalls of the internal constructor - responsible for creating the object - to false. This ends up generating an exception.

What does this really mean in my case? It basically means that  I had to add a public Scriptable method to my canvas class in order to get the XML from my remote service. And yes, i'm using javascript and XMLHttpRequest object to make the cross-domain call and then calling the scriptable method and passing it the XML I've received. ironic, right? I mean, this shouldn't really be needed and I'm hoping that future versions remove this ridiculous restriction.

And i think this sums up my experiences...

Dynamic data pages: listing your tables and views
Fri, May 18 2007 23:54

The DynamicNavigator control does what its name tell you: it'll build you a list that lets you navigate to pages that show your table's data. As you might expect, the control will use an ASP.NET UI control (in this case, a Menu) to list the tables/views presented on your db.

It's important to note that, by default, the control will only list the tables whose name match existing pages in your app. For instance, going back to the previous example, if you only have a page name Students and you add a DynamicNavigator to a page, you'll only get an entry called Students that points to your Students.aspx page.

This can be changed by tweeking the showAlltables attribute of the dynamicDataControls element in the web.config section. Setting it to true is all that it takes for the control to show you a complete list of tables and views. And in this case, it'll let you navigate to an automatically generated page, if there isn't one with the name of the table, or to an existing page that has the same name as your table.

Before ending this short post, I believe there's still time to mention the 2 new properties exposed by the control: IncludeTables and IncludeViews. They do exactly what you think: they let you choose if you're showing the tables, the views, both or none (which is a dumb thing to do, but possible, since you can set bot properties to false).

by luisabreu | with no comments
Filed under:
Silverlight 1.1 layout system and controls framework
Thu, May 17 2007 22:35

Dave Relyea has just published a framework with several controls. Go get them!

by luisabreu | with no comments
Filed under:
Calling javascript methods from your Silverligh app
Thu, May 17 2007 21:35

Well, sort of. To be able to do this, there are some prerequisites:

  • The Canvas type must be annotated with the ScriptableAttribute;
  • You must expose an event which the js code on the page should handle;
  • You must register your control with the WebApplication object by calling the RegisterScriptableObject method.

Here's a quick example (just the important parts):

[Scriptable]
public partial class Demo: Canvas{

   public void Page_Loaded( object o, EventArgs e ){
       InitializeComponent();
       //register this object so that it's accessible from JS
       WebApplication.Current.RegisterScriptableObject( "Managed", this );
   }

   [Scriptable]
   public event EventHandler SomethingHappened;

   //more code

}

Now, on your html page, you can handle the Load event of the Silverlight control so that you can hook up the SomethingHappened event with a custom js method:

function handleLoad( sender, e ){
   sender.Content.Managed.SomethingHappened = myMethod; //myMethod is a js function
}

function myMethod( sender, e ){
}

And that's it (i didn't show the code for firing the event because it's just like you do in traditionat .NET programming).

Notice how the name used during the registration is "added" by the Silverlight  control to the Content property, letting you access all the ScriptableAttribute annotated elements from js code...

Btw, do note that besides events, you can also expose other elements from your Silverlight types (which I'll talk in a future post). Still regarding the events, you can also use a custom EventArgs type and it'll get passed to the js method. When you do this, you should also annotate your custom EventArgs class with the ScriptableAttribute and make sure that all the elements that you want to use from js are of type int, double, string or ScriptableObject (complex types should be serialized into JSON and passed as strings). If you don't follow these rules, you'll get an exception during the RegisterScriptableObject method call.

by luisabreu | 7 comment(s)
Filed under:
More Posts Next page »