Показаны сообщения с ярлыком Silverlight. Показать все сообщения
Показаны сообщения с ярлыком Silverlight. Показать все сообщения

Silverlight 3 стал RTW = выпущен

пятница, 10 июля 2009 г.,

На сайте Microsoft доступны:

Silverlight: загрузка изображений и запись в файл

воскресенье, 10 мая 2009 г.,

Ситуация: надо c сервера загрузить изображение, например, Test.png и сохранить в файл, указанный пользователем на своем компьютере.
Для этого необходимо создать Silverlight приложение. Код MainPage.xaml заменить следующим:
<UserControl x:Class="SilverlightApplication5.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <Button x:Name="Load" Content="Load" Width="100" Height="30" />
</UserControl>
Код в MainPage.xaml.cs заменить следующим:
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;

namespace SilverlightApplication5
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            Load.Click += new RoutedEventHandler(Load_Click);
        }

        void Load_Click(object sender, RoutedEventArgs e)
        {
            UriBuilder ub = new UriBuilder(App.Current.Host.Source);
            ub.Path = "/Test.png";

            SaveFileDialog sfd = new SaveFileDialog();
            sfd.DefaultExt = ".png";
            if (sfd.ShowDialog() == false)
                return;

            WebClient wc = new WebClient();
            wc.OpenReadCompleted += (s, a) =>
            {
                if (a.Cancelled || a.Error != null)
                    return;

                using (var trg = sfd.OpenFile())
                {
                    int value;
                    while ((value = a.Result.ReadByte()) != -1)
                        trg.WriteByte((byte)value);
                }
            };
            wc.OpenReadAsync(ub.Uri);
        }
    }
}
В корень сайта добавить файл Test.png и запустить приложение.
В IE отобразится кнопка Load. После нажатия откроется диалог сохранения файла, в котором надо указать имя файла (расширение указывать не требуется) и нажать Save.

Динамические языки

суббота, 9 мая 2009 г.,

Основным отличием динамических языков программирования является возможность менять свой код во время исполнения, определять новые типы, модули, классы и методы.
Для реализации динамических языков на платформе .NET предназначен DLR (Dynamic Language Runtime), на базе которого созданы IronPython (реализация языка Python) и IronRuby (реализация языка Ruby).
Динамические языки также можно использовать в Silverlight; см. SDL (Silverlight Dynamic Languages SDK). Пример IronRuby в Silverlight. Подробнее о SDL и примеры использования ... см. здесь.

Веб-проигрыватель

вторник, 28 апреля 2009 г.,

Например, при загрузке веб-страницы в браузер надо начать проигрывание .mp3-файла. Сделать это можно с помощью Silverlight:
<html xmlns="http://www.w3.org/1999/xhtml" >
<head>
    <title></title>
    <script type='text/xaml' id="Ag">
        <?xml version='1.0' encoding='utf-8' ?>
        <MediaElement
            xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
            xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
            x:Name='media' Source='http://ipv4.fiddler:4139/Song.mp3' />
    </script>
</head>
<body>
    <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" style="height: 0px; width: 0px;">
        <param name="source" value="#Ag" />
    </object>
</body>
</html>
На странице есть вызов Silverlight, которому передается xaml, записанный в тег script.
Silverlight поддерживает Streaming и множество форматов, а также Server-Side Playlists.
Про адрес ipv4.fiddler - здесь.

Что такое Silverlight


Silverlight - это плагин для браузера. Скачать можно с сайта Microsoft (около 5MB). Silverlight работает в IE и в FF; также есть версия для Mac. Будет работать и в смартфонах. Подробнее здесь.

Silverlight реализован в виде ActiveX.

Данные из системного реестра для версии 3.0:
  • ProgId: AgControl.AgControl
  • CLSID: {DFEAF541-F3E1-4c24-ACAC-99C30715084A}
  • InprocServer32: С:\Program Files\Microsoft Silverlight\3.0.40307.0\npctrl.dll
Ag - это аргентум = серебро.

Силверлайт шутливо называют сервелат - есть такая колбаса :)

Silverlight служит для отображения xaml - это язык разметки с xml-синтаксисом. Поведение отображения можно задать/определить с помощью языка программирования C#. То есть можно сказать, что Silvelight - это "прокачанный" браузер, только вместо html используется xaml, а вместо jscript используется C#.

Разрабатывать Silverlight-приложения можно в Visual Studio с установленным Silvelight Tools (все это бесплатно).

Дополнительная информация на сайте silverlight.net

Динамическая загрузка скриптов

понедельник, 27 апреля 2009 г.,

Например, на веб-сайте в папке Script есть файл JScript.js:
function Test()
{
    alert("TEST");
}
В какой-то момент времени требуется из Silverlight вызвать загрузку .js-файла и выполнение функции Test. При этом загрузка файла должна происходить после каждого его изменения. Это можно сделать следующим образом в Silverlight:
ScriptHelper.Invoke("/Scripts/JScript.js?guid=" + Guid.NewGuid(), () =>
{
    HtmlPage.Window.Invoke("Test");
});

В метод Invoke передается путь к файлу. Guid используется для того, чтобы файл не кешировался браузером.
Принцип работы метода: создается тег SCRIPT; добавляется на веб-страницу в тег HEAD; происходит перехват события onreadystatechanged и в его обработчике проверяется состояние SCRIPT.readyState; если loaded, то вызвать метод в Silverlight.
Ниже код класса с extension method'ами:
public static class ScriptHelper
{
    public static HtmlElement FindByUri(string uri)
    {
        foreach (var script in HtmlPage.Document.GetElementsByTagName("script"))
        {
            if (string.Equals((string)script.GetProperty("src"), uri, StringComparison.OrdinalIgnoreCase))
                return (HtmlElement)script;
        }
        return null;
    }

    public static ScriptReadyState ReadyState(this HtmlElement scriptTag)
    {
        return (ScriptReadyState)Enum.Parse(typeof(ScriptReadyState), (string)scriptTag.GetProperty("readyState"), true);
    }

    public enum ScriptReadyState
    {
        Uninitialized = 0,
        Loading = 1,
        Loaded = 2,
        Interactive = 3,
        Complete = 4
    }

    public static void OnLoaded(this HtmlElement scriptTag, Action callback)
    {
        if ((int)scriptTag.ReadyState() > 1)
        {
            callback();
        }
        else
        {
            // обработчик событий
            EventHandler<HtmlEventArgs> eh = (s, e) =>
            {
                // проверить событие и состояние и вызвать handler
                if (e.EventType == "readystatechange" && (int)scriptTag.ReadyState() > 1)
                    callback();
            };

            // подключить обработчик
            scriptTag.AttachEvent("onreadystatechange", eh);
        }
    }

    // handler - в IE вызовется раньше, чем скрипт будет выполнен;
    public static void Invoke(string scriptUri, Action callback)
    {
        HtmlElement script = FindByUri(scriptUri);
        if (script == null)
        {
            // создать тег и добавить на страницу в тег HEAD;
            script = Create(scriptUri);
            var head = (HtmlElement)HtmlPage.Document.GetElementsByTagName("head").FirstOrDefault();
            head.AppendChild(script);
        }

        script.OnLoaded(callback);
    }

    public static HtmlElement Create(string scriptUri)
    {
        // создать тег скрипта
        var js = HtmlPage.Document.CreateElement("script");
        js.SetProperty("type", ScriptType);
        js.SetProperty("src", scriptUri);
        return js;
    }

    public static string ScriptType = "text/javascript";
}

Если js-функции не существует, то получим ошибку ... см. здесь.
Код работает в IE.

Использование JQuery в Silverlight

воскресенье, 26 апреля 2009 г.,

Вместе с ASP.NET MVC поставляется JQuery (краткое описание).
Предположим, что Silverlight-приложение используется на одной из страниц ASP.NET MVC проекта, на которой есть вызов JQuery. Т.е. в html-коде страницы в head указан тег:
<script type="text/javascript" src="Scripts/jquery-1.3.2.min.js"></script>
Требуется получить границы тега button:
<button id="btn">test</button>
Решение: использовать JQuery-функцию offset.
Для этого в Silverlight-приложение надо добавить следующий extension method:
public static class JQueryHelper
{
    public static Rect GetBounds(this HtmlElement el)
    {
        ScriptObject jqo = HtmlPage.Window.CreateInstance("$", new[] { el });
        return GetBounds(jqo);
    }

    private static Rect GetBounds(ScriptObject jqo)
    {
        ScriptObject res = (ScriptObject)jqo.Invoke("offset");
        return new Rect(
            (double)res.GetProperty("left"),
            (double)res.GetProperty("top"),
            (double)jqo.Invoke("width"),
            (double)jqo.Invoke("height")
        );
    }
}
Координаты кнопки можно получить следующим образом:
Rect rect = HtmlPage.Document.GetElementById("btn").GetBounds();
System.Diagnostics.Debug.WriteLine(rect);

Как проверить existance JavaScript-функции

четверг, 23 апреля 2009 г.,

Из Silverlight-приложения можно проверить existance (существование) функции с помощью следующего метода:
bool res = HtmlPage.Window.IsFunctionExists("MyFunc");
Метод вернет true для функции, которая определена в теге SCRIPT на странице или определена в подгружаемом .js-файле (например: <script type="text/javascript" src="Silverlight.js"></script>).
Метод определен в следующем классе:
public static class FunctionHelper
{
    public static bool IsFunctionExists(this HtmlWindow wnd, string functionName)
    {
        return (bool)wnd.Eval("typeof " + functionName + " == \"function\"");
    }
}

Как получить текст JavaScript-функции


Если имя JavaScript-функции известно, и функция определена в одном из тегов SCRIPT на веб-странице, либо она находится в отдельном .js-файле, то ее текст можно получить в Silverlight-приложении следующим образом:
var tmp = HtmlPage.Window.Eval("'' + MyFunc;");
Если ''+ не указать, то в tmp окажется ссылка на System.Windows.Browser.ScriptObject;
Если функция не определена, то при вызове метода Eval в IE8 всплывет диалог Webpage Error с вопросом: Do you want to debug this webpage? This webpage contains errors that might prevent it from displaying or working correctyly. If you are not testing this webpage, click No.
После закрытия диалога в Silvelight-приложении получим System.InvalidOperationException.

Решение:
public static string GetFunctionCode(this HtmlWindow wnd, string fname)
{
    return (string)wnd.Eval("(typeof " + fname + " == 'function') ? ('' + " + fname + ") : null;");
}

Как получить текст script'ов в Silverlight


С помощью метода GetJavaScripts можно получить список скриптов, размещенных на веб-странице:
foreach (string script in HtmlPage.Document.GetJavaScripts())
{
    System.Diagnostics.Debug.WriteLine(script);
}
Метод находит все теги SCRIPT и отбирает только те, у которых есть атрибут type="text/javascript".
Для использования метода необходимо в Silverlight-приложение добавить следующий код:
public static class ScriptHelper
{
    public static IEnumerable<string> GetJavaScripts(this HtmlDocument doc)
    {
        return doc.GetScripts("text/javascript");
    }

    public static IEnumerable<string> GetScripts(this HtmlDocument doc, string type)
    {
        Regex reg = new Regex(@"<script.+?type=" + type + ".*?>", RegexOptions.Singleline | RegexOptions.IgnoreCase);
        foreach (var scr in doc.GetElementsByTagName("script"))
        {
            string html = scr.GetProperty("outerHTML") as string;
            if (reg.IsMatch(html))
                yield return html;
        }
    }
}

Если скрипт находится в отдельном файле, то его код с помощью этого метода недоступен (в html получим, например: "\r\n<SCRIPT type=text/javascript src=\"Silverlight.js\"></SCRIPT>");

Вызов JavaScript функции из Silverlight


Представим себе, что требуется периодически обращаться к сервису, например, за какими-то зашифрованными данными, обрабатывать их, результат выводить на страницу.
Понятно, что JavaScript в такой ситуации не поможет, но можно использовать Silverlight. Для этого надо:
1) в .html- или .aspx-файл в тег body добавить "невидимый" Silverlight:
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" style="width: 0px; height: 0px;">
      <param name="source" value="ClientBin/App.xap" /></object>
Ширина и высота равны 0. Если указать style="display: none;", то Silverlight не загрузится.
2) в тег head добавить функцию, которая вызывается из Silverlight:
<script type="text/javascript">
    function ShowResult1(val) {
    }
</script>
3) в Silverlight-приложение добавить, например, следующий код:
ThreadPool.QueueUserWorkItem((state) =>
{
    for (int i = 0; i < 1000; i++)
    {
        // имитация длительной обработки
        Thread.Sleep(1000);
        // передача данных в JavaScript функцию
        this.Dispatcher.BeginInvoke(() => HtmlPage.Window.Invoke("ShowResult1", DateTime.Now.Ticks));
    }
});
В результате открытия веб-страницы в браузере произойдет загрузка Silverlight-приложения, в котором будет запущен рабочий поток с циклом на 1000 итераций. При каждой итерации данные передаются в JavaScript-функцию на веб-странице.

Постеры

понедельник, 20 апреля 2009 г.,

Перехват событий Silverlight в WinForms

понедельник, 13 апреля 2009 г.,

Silverlight можно использовать в WinForms-приложении не только для вывода Xaml. Также можно перехватывать сообщения, которые создаются в Silverlight.

За основу возьмем пример из сообщения "Silverlight в WinForms". Добавим в него неполное определение интерфейса IXcpControl (интерфейс наследует IDispatch, поэтому необязательно импортировать все свойства и методы):
[ComImport, Guid("1FB839CC-116C-4C9B-AE8E-3DBB6496E326"),
InterfaceType(ComInterfaceType.InterfaceIsIDispatch), ComVisible(true)]
public interface IXcpControl
{
    [DispId(0x20)]
    string Source { get; set; }

    [DispId(0x2c)]
    object OnLoad { get; set; }
}

И добавим наследника IReflect (используется в качестве посредника между Silverlight и WinForms; также можно использовать вместе с JavaScript):
public class Handler : IReflect
{
    public EventHandler _EventHandler;
    public Handler(EventHandler eh)
    {
        _EventHandler = eh;
    }

    [DispId(0)]
    public void Method()
    {
        if (_EventHandler != null)
            _EventHandler(this, EventArgs.Empty);
    }

    object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, System.Globalization.CultureInfo culture, string[] namedParameters)
    {
        if (name.Equals("[DISPID=0]", StringComparison.OrdinalIgnoreCase))
        {
            this.Method();
            return null;
        }
        throw new MissingMethodException(base.GetType().Name, name);
    }

    PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { return new PropertyInfo[0]; }
    MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) { return new MethodInfo[0]; }
    FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { return new FieldInfo[0]; }
    MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) { return new MemberInfo[0]; }
    MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) { return null; }
    FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) { return null; }
    MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { return null; }
    MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) { return null; }
    PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { return null; }
    PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) { return null; }
    Type IReflect.UnderlyingSystemType { get { return null; } }
}

Теперь надо создать форму и в ее конструктор поместить следующий код:
this.Size = new Size((int)(SystemInformation.WorkingArea.Width * .50f), 400);
string html = @"
    <SCRIPT id='_Xaml' type='text/xaml'>
        <?xml version='1.0' encoding='utf-8' ?>
        <Canvas
            xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
            xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'>
                <TextBlock FontSize='40' Foreground='Red'>Hello, World!</TextBlock>
        </Canvas>
    </SCRIPT>
    <OBJECT ID='_Ag' data='data:application/x-silverlight,' type='application/x-silverlight' Width='100%' Height='100%'>
        <PARAM NAME='Background' VALUE='#FFFADF' />
    </OBJECT>";
WebBrowser wb = new WebBrowser();
wb.DocumentCompleted += delegate
{
    var ag = wb.Document.GetElementById("_Ag").DomElement as IXcpControl;
    ag.OnLoad = new Handler(delegate { MessageBox.Show("Done!"); });
    ag.Source = "#_Xaml";
};

wb.DocumentText = html;
wb.Dock = DockStyle.Fill;
wb.Parent = this;
WebBrowser загрузит html и вызовет обработчик события DocumentCompleted. К событию OnLoad будет подключен обработчик, который вызовется из Silverlight после завершения загрузки xaml.