Lumber room
July 2009 30

Silverlight копипастим картинку из Clipboard

Перерыв кучу документации, выяснил, что «No we do not have clipboard support at this time. » :((

Решил только что данную проблему, спешу поделиться :)


Но получить и залить на сервер картинку из клипборда было жизненно необходимо, поэтому начал искать обходное решение.

В итоге пришел к связке (навеяно статьей Google Gears + Silverlight) ActiveX + JS + Silverlight
JavaScript выполняет роль «мостика» между компонентом ActiveX и Сильверлайтом.

Данное решение будет использоваться внутри локальной сети, поэтому есть возможность сразу установить всем ActiveX компонент с помощью групповой политики, прописать ресурс в Trusted Sites итд
Как решение для Internet данный метод не столь хорош :)

Для начала пишем ActiveX компонент


 public interface IClipboard
  {
    string Image { get; }
    string Text { get; set; }
  }

  [ClassInterface(ClassInterfaceType.AutoDual)]
  public class ClipboardProxy : IClipboard
  {

   public string Image
    {
      get
      {
        Image img = Clipboard.GetImage();
        if (img == null)
          return null;

        string fileName = Guid.NewGuid().ToString().Split(new char[] {'-'})[0] + ".png";

        PutFile(fileName, img);

        return fileName;
      }
    }

    public string Text
    {
      get
      {
        return Clipboard.GetText();
      }
      set
      {
        Clipboard.SetText(value);
      }
    }  }


* This source code was highlighted with Source Code Highlighter.


Текст из клипборда можно получать и без использования ActiveX, через объектную модель браузера, но я на всякий случай сделал и это.

Cохраняем картинку локально и передаем ее на удаленный сервер


  private void PutFile(string name, Image img)
    {
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri("http://helpdesk/ServicePages/upload.jsp"));

      request.Credentials = CredentialCache.DefaultNetworkCredentials;

      string folder = Environment.GetFolderPath(Environment.SpecialFolder.InternetCache);
      folder += "\\ " + name;

      img.Save(folder);
      FileInfo fileInfo = new FileInfo(folder);

      request.PostMultiPartAsync(new Dictionary<string, object> { { "uploadfile", fileInfo } }, new AsyncCallback(asyncResult =>
        {
          HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asyncResult);

          Stream responseStream = response.GetResponseStream();
          StreamReader reader = new StreamReader(responseStream);

          string s = reader.ReadToEnd();

          if (response.StatusCode == HttpStatusCode.OK)
          {

          }

          response.Close();
         
        }));

    }


* This source code was highlighted with Source Code Highlighter.


Не забываем выставить в настройках библиотеки Make Assembly COM-Visible (Свойства проекта — Application — Assembly Information)
и зарегистрировать ее с помощью команды:
regasm <имя сборки>.dll /tlb /codebase

В коде использован хелпер для отправки multipart form, ссылку где подсмотрел не нашел :(

Пишем функцию-мостик


 <script language="javascript">
  <!-- Load the ActiveX object -->
  var xClipboard = new ActiveXObject("Megafon.ClipboardHelper.ClipboardProxy");

  function GetClipboardImage()
  {
    
    return xClipboard.Image;  
  }

 </script>
  

* This source code was highlighted with Source Code Highlighter.


Функция возвращает имя файла котрое мы залили на сервер с помощью ActiveX-компонента
была мысль передавать byte[] но это я не поборол… JScript падал с ошибкой :(
Тогда можно будет не отправлять картинку на сервер, а использовать их сразу внутри сильверлайта.
Для моей задачи как раз нужно было отправлять скриншот на сервер, поэтому мне такое решение подошло.

Последний шаг — вызов из сильверлайта, я повесил обработчик на кнопку F12 в окне ввода описания


  private void tbxDescription_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
    {

      if (e.Key == (Key.F12))
      {
        this.Dispatcher.BeginInvoke((delegate()
        {
          object obj = HtmlPage.Window.Eval("(function(){ return GetClipboardImage(); })()");

          if (obj != null)
          {
            _attach.Add(new AttachItem() { FileName = obj.ToString() });
          }

        }));
      }     

    }


* This source code was highlighted with Source Code Highlighter.


Далее скрипт которому сильверлайт отправит данные формы содержит только имена файлов.
Сами файлы уже лежат на сервере ;)

Спасибо за внимание, надеюсь что данный прием будет кому-то полезен :)

ЗЫ: получить текстовое содержимое клипборда можно так:
  HtmlPage.Window.Eval("window.clipboardData.getData('Text')");

* This source code was highlighted with Source Code Highlighter.

+2
311 1
Comments 10
Top of the day