Welcome to RioterDeckers' HeadQuarter Sign in | Join | Help

GuidMarket SP1 - Next step into SilverLight

It's the tendency so why not a first service pack for the GuidMarket ?
More seriously, my first post about Silverlight (aka WPF/e) is especially dedicated to the technology evaluation that means the javascript code used to handle UI objects stay very "old school".

It's now interesting to provide a more flexible and improved code to extend the app with more objects and more features and thus to try to understand how to use this technology as well.

Download

 

What I modified


The first modification concerns the batch loading of the xaml streams which misses stability. So I wrote my own downloader javascript object that encapsulates the Downloader wpf/e object. I added an application object to easily extract the host object and the main canvas. The object enables me to bufferize the streams and the data that improves the synchronization between requests. I flushed the buffers within the main canvas when the loaded event is fired.

The second important modification concerns the "vista like" window loading. I added a WindowObject javascript object that manage the xaml on-the-fly creation and expose properties and methods to interact with the window. As the first version does not allow to create several windows on a same template, this version enables to create generate more than one window with different contents.

function WindowObject(name, title, width, height, parentObject, contentUri, callback)
{
  var
_width = width;
  var
_height = height;
  var
_title = title;
  var
_name = name;
  var
_parent = parentObject;
  var
_left = (window.screen.width - _width) / 2;
  var
_top = (window.screen.height - _height) / 2;
  var
_contentUri = contentUri;
  var
_callback = callback;
 
  this.Show = function
()
  {
    _application.MainWindow = this
;
    var __downloader = new
Downloader();
    var __loadEventArgs = new LoadEventArgs("windowtemplate.xaml", this._OnLoaded, null
)
    __downloader.LoopBack(__loadEventArgs);
  }

  this._OnLoaded = function
(args)
  {
    if(_parent == null) return
;
    var
__host = _application.GetHost();
    var
__child = __host.CreateFromXaml(args);

    _parent.children.add(__child);
    _parent.findName(Constants.WINDOW_TITLE).Text = _title;
    _parent.findName(Constants.WINDOW_ELEMENT)["Canvas.Top"
] = _top;
    _parent.findName(Constants.WINDOW_ELEMENT)["Canvas.Left"
] = _left;
    _parent.findName(Constants.OUTER_BORDER).Width = _parent.findName(Constants.INTER_BORDER).Width = _parent.findName(Constants.INNER_BORDER).Width = _width;
    _parent.findName(Constants.OUTER_BORDER).Height = _parent.findName(Constants.INTER_BORDER).Height = _parent.findName(Constants.INNER_BORDER).Height = _height;
    _parent.findName(Constants.BUTTON_CLOSE)["Canvas.Left"
] = _width - 51;
    _parent.findName(Constants.WINDOW_CONTENT).Width = (_width - 24);
    _parent.findName(Constants.WINDOW_CONTENT).Height = (_height - 37);
    _parent.findName(Constants.INNER_CONTENT_BORDER).Width = (_width - 14);
    _parent.findName(Constants.INNER_CONTENT_BORDER).Height = (_height - 37);
    _parent.findName(Constants.OUTER_CONTENT_BORDER).Width = (_width - 12);
    _parent.findName(Constants.OUTER_CONTENT_BORDER).Height = (_height - 35);
    _parent.findName(Constants.BUTTON_OK)["Canvas.Top"
] = (_height - 73);
    _parent.findName(Constants.BUTTON_OK)["Canvas.Left"
] = (_width - 115);

    _LoadContent(_contentUri);
  }

  this.Close = function
()
  {
    var
__window = _parent.findName(Constants.WINDOW);
    _parent.children.remove(__window);
    _application.MainWindow = null
;
  }

  var _LoadContent = function
(uri)
  {
    var __downloader = new
Downloader();
    var __loadEventArgs = new LoadEventArgs(uri, _OnContentLoaded, null
);
    __downloader.LoopBack(__loadEventArgs);
  }

  var _OnContentLoaded = function
(args)
  {
    var
__content = _application.GetHost().CreateFromXaml(args);
    _parent.findName(Constants.WINDOW_CONTENT).children.Add(__content);
    if(_callback != null
) _callback();
  }
}

 

Controls and ControlTemplates


I already said that control and controltemplate as we know in WPF do not exist in Silverlight. However, it's possible to have a similar feature by defining javascript objects which provide common characteristics and behaviors for UI objects. The graphical rendering can be loaded dynamically and synchronized by using xaml fragments loaded by the Downloader object.

The code bellow illustrates the definition of a ButtonBase control (JSON) which is rendered as a "vista like" button (without visual effects):

ButtonBase = function()
{
}
ButtonBase.prototype =
{
 
_content : null
,
  _height :
null
,
  _width :
null
,
  _left :
null
,
  _top :
null
,
  _visual :
null
,

 
initialize: function
initialize()
  {
   
var __fragment = '<Canvas Name="_buttonCanvas" Canvas.Top="'+ this.Top +'" Canvas.Left="' + this.Left + '" MouseLeftButtonUp="BLOCKED SCRIPTonclick">'
;
          __fragment +=
'<Rectangle Width="' + this.Width + '" Height="' + this.Height + '" RadiusX="2" RadiusY="2" Stroke="#A6A6A6" StrokeThickness="1">'
;
          __fragment +=
'<Rectangle.Fill>'
;
          __fragment +=
'<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">'
;
          __fragment +=
'<GradientStop Offset="0.0" Color="#FFF9F9F9" />'
;
          __fragment +=
'<GradientStop Offset="0.5" Color="#FFF3F3F3" />'
;
          __fragment +=
'<GradientStop Offset="0.5" Color="#FFE8E8E8" />'
;
         
__fragment += '<GradientStop Offset="1.0" Color="#FFD5D5D5" />'
;
          __fragment +=
'</LinearGradientBrush>'
;
          __fragment +=
'</Rectangle.Fill>'
;
          __fragment +=
'</Rectangle>'
;
          __fragment +=
'<Rectangle Width="' + this.Width + '" Height="' + this.Height + '" RadiusX="2" RadiusY="2" Stroke="#4AB2D9" StrokeThickness="1" />'
;
          __fragment +=
'<TextBlock Canvas.Top="7" Canvas.Left="37" FontFamily="Segoe UI, Verdana, Arial" FontSize="11" Foreground="Black" Text="' + this.Content + '" />'
;
          __fragment +=
'</Canvas>'
;

    var
__host = document.getElementById('wpfeControl1');
    _visual = __host.CreateFromXaml(__fragment);
  },

  attach :
function
attach()
  {
   
this
.initialize();
   
var __host = document.getElementById('wpfeControl1'
);
   
var __content = __host.findName("_content"
);
    __content.children.add(_visual);
  },

 
get_Top: function get_Top() { return
_top; },
  set_Top:
function
set_Top(value) { _top = value; },

  get_Left :
function get_Left() { return
_left; },
  set_Left :
function
set_Left(value) { _left = value; },

  get_Width :
function get_Width() { return
_width; },
  set_Width :
function
set_Width(value) { _width = value; },

  get_Height :
function get_Height() { return
_height; },
  set_Height :
function
set_Height(value) { _height = value; },

  get_Content :
function get_Content() { return
_content; },
  set_Content :
function
set_Content(value) { _content = value; }
}

The code of the object have to change the object itself but also the dependent Silverlight objects that are generated. However there is an important constraint because the Silverlight objects are not available by code until they are added to their parent. It's possible to either read xaml fragment such as above or load xaml from a file as the WindowObject of the GuidMarket application. Indeed, the .xaml files could be regarded as much templates.

 

The code below shows how to create a new instance of our ButtonBase and how to add it to a parent object as a Canvas. In this sample I decided to use an attach method to render the control but in a real application, you should have to create a custom object manager to add and retrieve the controls and to release resources when they are removed from their parents.

var _buttonBase = new ButtonBase();
_buttonBase.Content = "OK";
_buttonBase.Width = 100;
_buttonBase.Height = 30;
_buttonBase.Top = 10;
_buttonBase.Left = 10;
_buttonBase.attach();

Doubtful programmability


For the time being, I think Silverlight is not very flexible. A dynamic application needs too many asynchronous loadings. I had many problems between the asynchronous loading with the Atlas ScriptManager and the WPF/e Downloader object (and I don't speak about the permanent 'unexpected error' and other 'unknown exception' that everytime explode directly on your face).

I think the first real application need to be designed with more common controls and by creating custom controls. Custom controls can be developed but with too many code, the application needs a mediator object to handle them efficiently, to maintain the correct synchronization between WPF/e objects and javascript objects and to be able to raise custom events.

We may hope an efficient coupling between a more extended object model and Script# with the next CTP. While waiting, read the Nikhil Kothari's blog for more information...

 

Download new version

Published Tuesday, April 24, 2007 7:23 AM by Chaz
Filed Under:

Comments

No Comments
Anonymous comments are disabled