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.
    Share post
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 10

      0
      Если установить ActiveX в доверенные, то можно не только с клипбордом возиться, а черта лысого с машиной спарить, вплоть до получения контроля над системой. Это все равно, что покупать для избавления огорода от вредителей танк.
        0
        Нужно было получить картинку из клипборда. (скриншот ошибки в приложении например)
        Компонент будет работать только в корпоративном intranet, поэтому для данных условий решение на мой взгляд вполне работоспособное.
          0
          А скриншот делает пользователь? Если это делает стороннее приложение, почему бы не отправлять его непосредственно на сервер.
            0
            Скрин делает пользователь и прикрепляет его к заявке с описанием проблемы :)
        0
        Вот это костыль так костыль! :)
          0
          Вообще в интернете решения данной задачи я не нашел… )
          Пришлось выдумывать свой костыль :)
          0
          Казалось бы, при чем тут Сильверлайт… :)

          А разве для доверенного приложения нельзя вызывать WinAPI из Сильверлайта?
            0
            Честно говоря, не нашел такого способа, если есть ссылки по данной теме — очень интересно было бы почитать!
              0
              Честно говоря, его и нет. Они, похоже, запретили вызов неуправляемого кода независимо от уровня доверия.
                0
                Видимо только и остается сооружать подобный мост через JS :((

          Only users with full accounts can post comments. Log in, please.