Thursday, July 24, 2008

Configuring and running Mono ASP.NET 3.5 (AJAX.NET) on Linux computers

Before we will start, we should install Linux. To do this, you can download any of LiveCDs with live installation. Officially, Mono supported only on one free Linux - openSuse. However, you can make it work on any RedHat (and its alternatives), OpenSolaris. It works, but unsupported on Debians, Ubuntu and Maemo. We’ll stick to openSuse by now.

image

Let’s install it - OS

I’m assuming, that you’re installing Linux as the only OS on the machine, so insert liveCD (it can be either Gnome or KDE) and wait for Linux to run. It will run live image directly on your machine without installation.

When it’ll up, you’ll see liveInstall icon in your desktop. Click it and skip first two screens (it is only language and local settings). Next screen (disk partitions) is necessary for us.

On this screen, first delete all automatic partitions. The only one main partition will remain (/DEV/SDA or /DEV/HDA). Next you should choose non-LVM option and then start creating partitions.

Create first partition with mount point /boot and size of 100Mb. File system for this partition should be ext3.

Create second partition with file system SWAP (you will not have mount point) and set the size twice bigger, then RAM amount.

Create last partition with mount point / and all remaining size on disk.

All other steps are optional, you can just click Next button.

After about 10 minutes you’ll have up and running openSuse system. (If you forgot to remove CD, choose HardDisk as boot option)

Web Server installation

Now we have to install web server. You can choose either Apache, FastCGI  or use build-in server within Mono – XSP. We’ll choose Apache

Goto “Computer” it’s in the same place as Start button :) and choose YaST. You’ll be asked for admin password, you entered while installing the system.

Now in the Filter field, type “Install”. Choose “Software Management” from the available programs at right. Now, when Package Selection dialog opens, type “apache”, you’ll find apache2. Select it and click Install. Apache will move to the right column. Optionally, you can install also prefork and utils packages.

Now hit “Apply” to install it. Within two minutes, you’ll be asked to log off and log on. Do it.

By now apache is not running, you should run it and set it starts automatically. To do this, enter terminal window (you can either do it from “Computer” menu or right clicking desktop).

You need elevation to administrate startup programs. So type: “su –“ and enter your password. Terminal color turns red. Type “chkconfig apache2 on”. Now you should check whether it done, so type: “chkconfig apache2 –list”. You should see “On” near number 3 and 5.

To run apache manually, just type “/etc/init.d/apache2 start” to stop “/etc/init.d/apache2 stop”, to restart “/etc/init.d/apache2 restart” and to check the status “/etc/init.d/apache2 status

We done, apache is up and running. Now we should install mono

Mono installation

Start with the same YaST but this time, type “mono” – you’'ll get a lot of programs. To simplified installation, choose (or type) mono-complete. This will all available Mono modules.

After Mono will be installed, you should install also apache2-mod_mono to make possible running ASP.NET mono pages in Apache. do this.

Log off – log on and move to configuration

Mono configuration

Now it’s time to configure what ASP.NET pages you want to run. We want ASP.NET 2.0, so we should run mono apache mode for this version. To do this, go to the terminal, elevate yourself (su –) and type following: “vi /etc/apache2/httpd.conf” This will open VI editor with apache configuration file in it.

Now it’s time to learn VI a little. To start editing, you should type “A” – it will write “INSERT” in the lower left corner. To return to the command mode, hit escape key. To save (from command mode) “:w” to exit and save:wq” to exit without save:q!”. To find/” and string the pattern you are looking for.

Now go the the very end of the file  and write under Include “/etc/apache2/vhosts.d/*.conf” following:
(to short string “[D]” is your virtual directory (slash blank is root), “[P]” is physical path to your site without trailing slash)

MonoServerPath default /usr/bin/mod-mono_server2
Alias [D] “[P]”
AddMonoApplications default “[D]:[P]”
<Location [D]>
SetHandler mono
</Location>

So, if your site is MySite and it is in /srv/www/htdocs/MySite, this section will looks as following:

MonoServerPath default /usr/bin/mod-mono_server2
Alias /MySite “/srv/www/htdocs/MySite”
AddMonoApplications default “/MySite:/srv/www/htdocs/MySite”
<Location /MySite>
SetHandler mono
</Location>

If you want to turn it to the root site, this will looks following:

MonoServerPath default /usr/bin/mod-mono_server2
AddMonoApplications default “/:/srv/www/htdocs/MySite”
<Location />
SetHandler mono
</Location>

Now, we’ll add mono administrative site to be able to restart mono only without touching apache itself. To do this, after last </Location> you should add following:

<Location /mono>
SetHandler mono-ctrl
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>

I think it’s very clear what it did :)

If you have more, then one site and want to configure mono differently for each one of those, you should add VirtualHost section. To do this, include your configuration in to

<VirtualHost [IP and port you want, for example 1.1.1.1:80 or *:80 for all IPs on port 80]>
ServerName [Name you want]

</VirtualHost>

We done. Restart apache and enter the url you set (for example http://localhost/MySite/)

Working? Good. You finished.

Not working (familiar yellow error 500 screen)? Keep reading…

Debugging Mono website

Do you remember, that you have no development environment in this machine? You can install it, or download Mono liveCD with openSuse. But before doing it, please note, that GTK# (it’s devenv) is not very user friendly. It even worse, then Eclipse. So let’s try to understand first whether we can fix small compatibility problems without entering code.

The most convenient method to debug web site on Mono is by using XSP and XSP2 mini web servers. Just enter the directory of the site and run it. By default you’ll be able to access the site by using “http://localhost:8080” (it also be written for you). Enter and notice whether you have any errors in console. No? Keep doing

The most common problem is “error 500” with nonsense stack. If it contains ScriptManager error Type not found, the problem is in Web.config file. Try to regenerate it to be compatible to Mono (for example, Mono has different version of System.Web.Extensions assembly. In ASP.NET 3.5 it has version 3.5, Mono has only 1.0.61025.0 (the old AJAX.NET). To recreate your web.config all you have to do is to execute “mconfig af AJAX Web.config” It will create default web.config file, supports System.Web.Extensions (AJAX features).

Not helped? Keep doing. Let’s look another time into the stack – if it contains errors in “EnablePageMethods” or “ShouldGenerateScript” or “EncryptString” – the problem is serialization. Mono has very limited support for JSON, XML and SOAP serialization. Try to look into your code and notice if you have classes, marked with [Serializable] or you are transferring your own classes by using PageMethods. If so, replace it with regular strings (my grandma serialization).

Person p = new Person();
string sstr = string.Format(“{0}|{1}|{2}|{3}”, p.FirstName, p.LastName, p.Age, p.Wage);
return sstr;

var sstr = persons[i].split("|");
var p.FirstName =  sstr[0];
var p.LastName =  sstr[1];
var p.Age =  sstr[2];
var p.Wage =  sstr[3];

Not helped? Try to rename “Bin” directory into “bin” “mv Bin bin –r”. Actually this was fixed in latest versions of Mono, but who knows?…

No? Check whether you have partial classes, which is not supported by Mono. If so, recompile it like this

mcs /t:library /out:bin/test.dll –r:System.Web –r:System.Data –r:System.Web.Services –r:System.Web.UI.Controls test.aspx.cs

If you have Generics in your code, you should use gmcs, rather then mcs.

Not helped? It looks, that you have to either install Mono on your Windows machine and debug your code with it. Or, alternatively install GTK# and do in on Linux.

But wait, before doing such big step, install and check the binary compatibility of your code. To do this, you need “Moma” – a simple tool, that tell you if everything is ok for Mono in your assemblies.

Good luck and see you in my forthcoming TechEd session, where I’m presenting openSuse, running UDP multicast server with ASP.NET 3.5 extended methods (It uses recompiled ISAPI filters for apache, rather then regular limited AJAX support in Mono)

Have a nice day and be good people.

Tuesday, July 22, 2008

Choosing new notebook

Hi, Community Brain. It’s time for me to change my old good Dell Latitude D820. I need performant machine and following the results of my findings. It’s really important for me to know your opinion about those choices. Also, if you have additional choices, I’d be happy to hear about it.

  Dell Precision M630 HP 8710W Lenovo T61p
  image image image
Processor Intel® Core 2 Duo T9500 (2.6GHz, 6Mb, L2 cache, 800MHz FSB) Intel® Core 2 Duo T9500 (2.6GHz, 6Mb, L2 cache, 800MHz FSB) Intel® Core 2 Duo T9500 (2.6GHz, 6Mb, L2 cache, 800MHz FSB)
Memory 4GB 667MHz DDR2 SDRAM (2x2048) 4GB 667MHz DDR2 SDRAM (2x2048) 4GB 667MHz DDR2 SDRAM (2x2048)
Video Card NVidia® Quadro® FX 3600M (512MB dedicated) NVidia® Quadro® FX 3600M (512MB dedicated) NVidia® Quadro® FX 570M (256MB dedicated)
Hard Drive 200GB SATA (7,200RPM) + fall sensor 200GB SATA (7,200RPM) 200GB SATA (7,200RPM) + disk encryption
Optical device 8X DVD +/- RW 8X DVD +/- RW Blue-ray 8X DVD +/- RW
Modem 56.6k v.92 56.6k v.92 --
Wireless Networking Intel PROWireless 4965 802.11 a/g/Draft-n Intel® Wireless LAN 802.11a/b/g/n Intel Wireless WiFi Link 4965AGN
Bluetooth Dell Wireless 360 Intel Bluetooth‏ Integrated Bluetooth PAN
Primary battery 9 Cell Li-Ion (80 Whr) 9 Cell Li-Ion w/XPP 3 yr warranty 9 cell Li-Ion Battery
LCD 17” WUXGA (1920x1200) UltraSharp + anti-glare 17” WUXGA+WVA (1920x1200) anti-glare 15.4” WSXGA+  (1920x1200)
Weight 8.5 lbs/3.8 kg 7.4 lbs/3.4 kg 7.3 lbs / 3.3 kg
Dimensions 1.6”(H) x 15.5”(W) x 11.3”(D) 1.3”(H) x 15.4”(W) x 10.8”(D) 1.4”(H) x 14.1”(W) x 10.4”(D)
       
Cons I saw Precision series in work – performance is not good enough for such configuration (for comparison, my old Latitude with the same hardware configuration worked much better) Everyone I asked, tell me, that HP machines are not reliable enough Keyboard layout is absolutely awful. It impossible to work with Fn and Ctrl swapped.
Graphic card is not strong enough
It’s 15.4”
Pros It is very reliable Very good performance
Very lighter
Good battery life
Absolutely reliable
Great performance
Outstanding battery life

 

What to do? What to choose? Please advice!

Thank you

Thursday, July 17, 2008

Arabic and Hebrew languages bidirectional support for Silverlight 2.0 beta 2

Those days, I’m, together with guys from Microsoft Egypt and Santeon, finishing development of bidirectional input and output support for Silverlight. I want you to take part in alpha testing of this solution. Please see the test form here and try it.

Also, you can download latest development build and try it yourself. Please, if you’re in any issue, report it, by using issue tracker in CodePlex.

In order to use it, all you have to do is to use custom namespace within your project and then, you’ll be able to get almost all controls, you know, but with Arabic and Hebrew RTL and LTR support. You have to set one property: FlowDirection to change the rendering method (exactly as in WPF). Here an example of usage.

<UserControl x:Class="BidiTest2.Page"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:l="clr-namespace:System.Windows.BidiControls;assembly=BidiControls">

<l:TextBlock FlowDirection="LeftToRight" Text="שלום עולם"/>

<l:TextBox FlowDirection="RightToLeft" Text="{Binding Text, Mode=TwoWay}"/>

That’s all. Thank you for your cooperation.

image

Tuesday, July 15, 2008

Mobile version of this blog

10x to great service of mofuse, I have mobile version of this blog now. So bookmark it: http://m.0x15.net/

image image

Here the QR code for your convenience

image

Saturday, July 12, 2008

Quick Silverlight tip: Why my ActualWidth and ActualHeight equal 0?

If you’ll try to use ActualWidth and ActualHight of controls with explicitly set Width and Height, you’ll not see any problem, however, if your control sits inside other control, ActualWidth and ActualHeight properties will be equal to 0. Why this and how to fix it?

Actually, measurement and layout pass in Silverlight run asynchronously, thus it executed with or, even after, your code. So in order to fix it, you should measure ActualWidth and Actual Height asynchronously. So, instead of:

//get and use ActualWidth/ActualHeight

Use:

Dispatcher.BeginInvoke(delegate
{
  //get and use ActualWidth/ActualHeight
});

It will allows you to detect actual size of your control.

Have a nice day and be good people.

Tuesday, July 08, 2008

How to handle thickness

Yesterday, we spoke about type converters. We even, built simple generic enum converter. Today, we’ll create more complicated converter, that very missing in Silverlight – ThicknessConverter. During the post, I also explain about tokenizing values in Silverlight

image

What is Thickness ?

What is thickness in Silverlight? It’s

<Border BorderThickness=”6”/>

or

<Border BorderThickness=”6,4,3,2”/> or <Border BorderThickness=”6, 4, 3,2”/> or, even <Border BorderThickness=”6; 4; 3 ;2”/>

How to handle it?

Tokenizing strings

What you seen here is tokenized strings. We have to split them by known token (one and own for each string) and then we can parse it for converter. How to do this? Complicated – too much cases. But, basically, you have to get string, quote character and separator. Don’t forget to check for empty spaces

private void Initialize(string str, char quoteChar, char separator)
        {
            this._str = str;
            this._strLen = (str == null) ? 0 : str.Length;
            this._currentTokenIndex = -1;
            this._quoteChar = quoteChar;
            this._argSeparator = separator;
            while (this._charIndex < this._strLen)
            {
                if (!char.IsWhiteSpace(this._str, this._charIndex))
                {
                    return;
                }
                this._charIndex++;
            }
        }

Then we have to scan string to find tokens

private void ScanToNextToken(char separator)
        {
            if (this._charIndex < this._strLen)
            {
                char c = this._str[this._charIndex];
                if ((c != separator) && !char.IsWhiteSpace(c))
                {
                    Exceptions.ThrowInvalidOperationException("No Separator Found");
                }
                int i = 0;
                while (this._charIndex < this._strLen)
                {
                    c = this._str[this._charIndex];
                    if (c == separator)
                    {
                        this._foundSeparator = true;
                        i++;
                        this._charIndex++;
                        if (i > 1)
                        {
                            Exceptions.ThrowInvalidOperationException("Empty Token Found");
                        }
                    }
                    else
                    {
                        if (!char.IsWhiteSpace(c))
                        {
                            break;
                        }
                        this._charIndex++;
                    }
                }
                if ((i > 0) && (this._charIndex >= this._strLen))
                {
                    Exceptions.ThrowInvalidOperationException("Emply Token Found");
                }
            }
        }

why not just split? Because it is not generic solution for strings with empty tokens, which is absolutely invalid. Another reason of using such helper is performance. String operation are not very fast things, thus we’ll check only the number of tokens required for future operations.

Also, we should make sure, that all tokens are required and get rid of unnecessary parts of the string, such as leading spaces, control characters etc. Now, when we have tokenized string, we can start building converter

Building thickness converter

Actually, the most significant part of this converter is tokenization , thus the most important override method for such converter is ConvertFromString

public override object ConvertFromString(string text)
        {
            Thickness res = new Thickness();
            TokenizerHelper helper = new TokenizerHelper(text);
            double[] numArray = new double[4];
            int index = 0;
            while (helper.NextToken())
            {
                if (index >= 4)
                {
                    index = 5;
                    break;
                }
                LengthConverter lc = new LengthConverter();
                numArray[index] = (double)lc.ConvertFromString(helper.GetCurrentToken());
                index++;
            }
            switch (index)
            {
                case 1:
                    res = new Thickness(numArray[0]); break;
                case 2:
                    res = new Thickness(numArray[0], numArray[1], numArray[0], numArray[1]); break;

                case 4:
                    res = new Thickness(numArray[0], numArray[1], numArray[2], numArray[3]); break;
                default:
                    typeof(Thickness).ThrowConvertFromException(text); break;
            }
            return res;
        }

The only thing to remember is to check whither we can convert from the type received from XAML

public override bool CanConvertFrom(Type sourceType)
        {
            switch (Type.GetTypeCode(sourceType))
            {
                case TypeCode.Int16:
                case TypeCode.UInt16:
                case TypeCode.Int32:
                case TypeCode.UInt32:
                case TypeCode.Int64:
                case TypeCode.UInt64:
                case TypeCode.Single:
                case TypeCode.Double:
                case TypeCode.Decimal:
                case TypeCode.String:
                    return true;
            }
            return false;
        }

Have a nice day and be good people. Stay tuned for future work process items.

Monday, July 07, 2008

Work process: How to use and build type converters

Today, I want to start new tag - “Work process”. Here I’m going to publish partial classes, fixes, small utilities, I’m building for myself or clients to help in work process. I’ll give an example: currently, I’m working on BiDi support for Silverlight 2.0 (beta 2 to RTM). During the work process, I need to write different classes, such as converters, string utilities, exception helpers etc.

ZK4Y7556 
© Imaginary copyright by  Noel Hendrickson

So, today I’ll public general type converter for generic classes.

What is type converter?

TypeConverter is a service attribute, used to help rendering engine to convert XAML string (usually it strings) to the type, you require in your class implementation. Here an example:

In your custom class you have dependency property of type TextAlignment

public TextAlignment TextAlignment
       {
           get { return (TextAlignment)GetValue(TextAlignmentProperty); }
           set { SetValue(TextAlignmentProperty, value); }
       }

In XAML code it will be used as:

<MyControl TextAlignment=”Left”/>

But, what you’re actually transfer to your class is string “Left”, when you need enum TextAlignment.Left, how to convert it? This for we’re using type converters

Attribute usage

In order to “tell” framework to use your type converter, you should mark target property with special attribute TypeConverterAttribute. Also, you can provide default value to your property by using another attribute DefaultValueAttribute. This will looks as following:

[TypeConverter(typeof(MyTextAlignmentTypeConverter))]
[DefaultValue(TextAlignment.Left)]
public TextAlignment TextAlignment
{
  get { return (TextAlignment)GetValue(TextAlignmentProperty); }
  set { SetValue(TextAlignmentProperty, value); }
}

How to build type converter

In order to build type converter, all you have to do is to build your own class, derived from TypeConverter. It also can be generic class. Then, implement necessary methods, that incorporate your business logic. Like this one, converter any enum value back and forward for TypeConverterAttribute

public class EnumValueConverter<T> : TypeConverter where T:struct
    {
        static EnumValueConverter()
        {
            if (!typeof(T).IsEnum) { Exceptions.ThrowInvalidOperationException("Cannot use this type for conversion"); }
        }

        public override bool CanConvertFrom(Type sourceType)
        {
            return Type.GetTypeCode(sourceType) == TypeCode.String;
        }

        public override object ConvertFrom(object value)
        {
            if (value == null)
            {
                typeof(T).ThrowConvertFromException(value);
            }
            if (value is string)
            {
                return ConvertFromString(value as string);
            }
            return (T)value;
        }

        public override object ConvertFromString(string text)
        {
            return (T)Enum.Parse(typeof(T), text, true);
        }

        public override string ConvertToString(object value)
        {
            return Enum.GetName(typeof(T), value);
        }
    }

Final result

Now, when we built converter and know how to use it, we can easily set it to any DependencyProperty requires conversion from / to enum

[TypeConverter(typeof(EnumValueConverter<LineStackingStrategy>))]
public LineStackingStrategy LineStackingStrategy
{
  get { return (LineStackingStrategy)GetValue(LineStackingStrategyProperty); }
  set { SetValue(LineStackingStrategyProperty, value); }
}

[TypeConverter(typeof(EnumValueConverter<TextAlignment>))]
[DefaultValue(TextAlignment.Right)]
public TextAlignment TextAlignment
  {
   get { return (TextAlignment)GetValue(TextAlignmentProperty); }
   set { SetValue(TextAlignmentProperty, value); }
  }

[TypeConverter(typeof(EnumValueConverter<TextWrapping>))]
public TextWrapping TextWrapping
{
  get { return (TextWrapping)GetValue(TextWrappingProperty); }
  set { SetValue(TextWrappingProperty, value); }
}

We done, have a nice day and be good people.

Stay tuned for release of BiDi support for Silverlight 2.0, sponsored by Development Platform Evangelism unit of Microsoft Israel

Silverlight Visual Tree Investigation

Wait a moment. Silverlight has Visual and Logical Trees as well as WPF? Not exactly. The design more similar to how it was in WinForms (Parent-Child relationship). But dev team made all possible to make it syntactically similar to WPF. Let’s start

Challenge: Find and hold references to all element, contains text.

Solution: Recursive VisualTreeHelper (introduced in SL2.0 b2)

First of all we should know, that Silverlight is not ready for manufacture, thus direct references might produce memory leaks, thus we’ll use WeakReference to hold pointers to SL objects.

First step: We know for sure, that TextBox and TextBlock controls has Text property, that holds only text. Also TextBlock can hold Inlines collection with Runs and LineBreaks. Let’s find them all

internal static List<WeakReference> GetTextElements(this DependencyObject root)
        {
List<WeakReference> res = new List<WeakReference>();
if (root is TextBlock | root is TextBox)
         {
                res.Add(new WeakReference(root));
         }

Next, we know, that ContentControl can hold text directly inside Content property. We’ll find them too, but should check if it holds text inside…

else if (root is ContentControl)
            {
                (root as ContentControl).CheckAndAddStringContentControl(ref res);
            }

Now ItemsControl. It can hold inside either ContentElement, TextBox, TextBlock or other. So we should check inside it too.

else if (root is ItemsControl)
            {
                ItemsControl ic = root as ItemsControl;
                for (int i = 0; i < ic.Items.Count; i++)
                {
                    if (ic.Items[i] is ContentControl)
                    {
                        (ic.Items[i] as ContentControl).CheckAndAddStringContentControl(ref res);
                    }
                    else
                    {
                        List<WeakReference> tmp = (ic.Items[i] as DependencyObject).GetTextElements();
                        if (tmp != null && tmp.Count > 0)
                        {
                            res.AddRange(tmp);
                        }
                    }
                }
            }

And last, but not least is to dig into all child of each control.

else
            {
                int cnt = VisualTreeHelper.GetChildrenCount(root);

                for (int i = 0; i < cnt; i++)
                {
                    DependencyObject d = VisualTreeHelper.GetChild(root, i);
                    List<WeakReference> tmp = d.GetTextElements();
                    if (tmp != null && tmp.Count > 0)
                    {
                        res.AddRange(tmp);
                    }

                }
            }
            return res;

Step two: Check whether object contains text inside. This one is simple. If not, we’ll call the main method to inter inside the control and check deeper.

internal static void CheckAndAddStringContentControl(this ContentControl cc, ref List<WeakReference> res)
        {
            if (cc.Content is string)
            {
                res.Add(new WeakReference(cc));
            }
            else
                res.AddRange(cc.GetTextElements());
        }

We done. Now we have WeakReferences collection of all items, which contains text in our page.

Have a good day and be nice one to another.

Tuesday, July 01, 2008

Quick Silverlight Tip: How to access HTML DOM from Silverlight and Silverlight managed objects from HTML?

After my session yesterday, I got number of email from people, who have a problem to access HTML DOM from Silverlight and vice verse. I want to answer to all of you by this post.

Access HTML from Silverlight

You have not do anything special in Silverlight to access it.  Your friend is HtmlPage.Window object. For example, if I want to execute window.open JavaScript method from Silverlight, all I have to do is to call:

public void OpenWindow()

        {

HtmlPage.Window.Invoke("open", new object[] { "http://blogs.microsoft.co.il/blogs/tamir", "login", "resizable=1,width=646,height=436" });

        }

HtmlPage.Window.Invoke also returns Object – this is the response of function executed.

Access Silverlight Managed Objects from HTML

Here you should remember two things:

  • You should mark both class and member you want to access with special attributes ScriptableType (for class) and ScriptableMember (for member)
  • Register Scriptable object anywhere (for example in Constructor).

So, if you want OpenWindow method to be exposed from the Page class to HTML, you should use following code:

    [ScriptableType]
public partial class Page : UserControl    {
public Page() {
            InitializeComponent();
            HtmlPage.RegisterScriptableObject("Page", this);
        }

[ScriptableMember]
public void OpenWindow() {
object o = HtmlPage.Window.Invoke("open", new object[] { "http://blogs.microsoft.co.il/blogs/tamir", "login", "resizable=1,width=646,height=436" });
        }
}

That’s all, folks. Be good people and have a nice day.

Here the script of test application:

Page.xaml

<UserControl x:Class="DomAccessDemo.Page"

xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

Height="20">

<Grid x:Name="LayoutRoot" Background="White">

<Button Click="Button_Click" Content="Fun!"/>

</Grid>

</UserControl>

Page.xaml.cs

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.Browser;

using System.ComponentModel;

namespace DomAccessDemo

{

    [ScriptableType]

public partial class Page : UserControl

    {

public Page()

        {

            InitializeComponent();

HtmlPage.RegisterScriptableObject("Page", this);

        }

private void Button_Click(object sender, RoutedEventArgs e)

        {

            OpenWindow();

        }

        [ScriptableMember]

public void OpenWindow()

        {

object o = HtmlPage.Window.Invoke("open", new object[] { "http://blogs.microsoft.co.il/blogs/tamir", "login", "resizable=1,width=646,height=436" });

        }

    }

}

DomAccessDemoTestPage.aspx

<html xmlns="http://www.w3.org/1999/xhtml" style="height:100%;">

<head runat="server">

<title>Test Page For DomAccessDemo</title>

<script language="javascript">

function testSL()

        {

var xaml = document.getElementById("Xaml1");

            xaml.Content.Page.OpenWindow();

        }

</script>

</head>

<body style="height:100%;margin:0;">

<form id="form1" runat="server" style="height:100%;">

<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>

<div style="height:100%;">

<asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/DomAccessDemo.xap" MinimumVersion="2.0.30523" Width="100%" Height="100%" />

</div>

</form>

<button onmouseup="testSL();">Test</button>

</body>

</html>