如何制作依赖于System.Drawing命名空间的现有C#代码的Silverlight版本

时间:2010-12-09 18:19:03

标签: c# silverlight porting system.drawing

我们有很多C#2.0代码,它们严重依赖于System.Drawing命名空间。还有一些WinGDI依赖项(通过互操作)。

您如何建议解决制作功能相同的Silverlight版本代码的问题?我们希望尽可能多地重用代码,因为我们希望继续开发代码的两个版本。

也许你可以推荐一些文章/书籍?

更新:代码是一个非可视组件。不是申请。没有第三方依赖。

6 个答案:

答案 0 :(得分:4)

我在创建以前使用winforms构建的wpf / silverlight版软件方面有很棒的经验。这很难过,但在你的情况下,当你使用很多互操作和System.Drawing的东西时,实际上不可能做这样的事情。

对于cource来说,你总是可以尝试(并且你总是必须)将你的业务逻辑与接口分开,但在这种情况下(我希望是错的!),你的界面必须完全重新设计,因为winforms和wpf / silverlight架构的差异。

根据我的经验,这个问题以这种方式解决了:所有旧的winforms组件都保持不变,但所有新功能都是使用wpf构建的,有助于在winforms应用程序中注入wpf控件。

是的,有时它很奇怪,但它真的更有效率,而不仅仅是浪费你所有的旧代码,花费大量的时间和金钱到新的,这也是一样的。

答案 1 :(得分:3)

如果没有GUI且你仍在使用大量的System.Drawing我猜这个组件的作用与内存中图像的操作有关。

如果是这种情况,由于移植所有代码的成本非常高,如果可能的话,您可以考虑更改您的架构。

在服务器端使用旧代码,您可以在其中自由使用这些API,并通过某些Web服务向Silverlight应用程序公开所需的功能。如果组件没有GUI,那么它应该是非常可行的。

编辑:添加有关如何适合开发人员的建议

也许这可能仍然有效 - 如果您的开发人员计划在网页中部署此Silverlight控件,那么他可能有一个Web服务器,他可以在其上放置您的组件以供Silverlight代码访问。

如果开发人员计划在浏览器外模式下部署Silverlight代码,则可以创建一个嵌入旧组件的版本(例如作为COM对象)。

上述的另一种选择是将您自己的组件托管在服务器上,或者在某些公共云(如Windows Azure)上托管。

答案 2 :(得分:2)

这几乎是不可能的,因为WPF和Silverlight都与旧版本有根本的不同。如果您真的希望能够同时开发桌面和Web应用程序,那么使用WPF和Silverlight可能会更好。

唯一的问题是重用代码仍然很困难,因为Silverlight没有WPF所具有的所有功能。最重要的是,在Silverlight中访问数据的模型是完全异步的。

最好在Silverlight中构建应用程序,然后将该应用程序移植到WPF。

可能不是你想要的答案。

答案 3 :(得分:2)

根据您现有代码库的架构方式,这可能无法实现,但您可以在WPF中加载Forms控件,请参阅this example。如果您的遗留代码打包到控件中,您可能可以重用大量代码。我希望这会有所帮助。

答案 4 :(得分:1)

这是另一个疯狂的想法。

将所有System.Drawing,PInvoke,GDI等隔离到一个单独的组件中,并将其包装为ActiveX对象。

在您的网页中嵌入ActiveX对象,并使您的Silverlight应用程序以某种方式使用其服务。我想这需要网页级别的一些“管道”(例如,一个可以激活ActiveX对象的脚本,并通过文档或其他东西将结果公开给Silverlight应用程序)

这只是我最初的想法。我想它可以在很多方面得到改善。你怎么看? :)

编辑:如果您的Silverlight代码可以在浏览器外模式下运行,则Silverlight 4支持在Silverlight应用程序中嵌入ActiveX控件。这可能使您可以将所有旧实现包装在某些ActiveX中并从Silverlight中使用它。

答案 5 :(得分:1)

首先,您应该接受原始代码某些功能不会使其成为Silverlight版本。互操作,读写文件 - 由于安全原因或者不支持,这些内容要么被禁止。

要记住的第二件事是您的代码将被条件编译污染(如果您想继续支持从相同的代码库构建.NET版本)。

第三件事是 - 你必须编写一些新代码(而不是删除代码)。例如,您可能需要创建接受WriteableBitmap的新方法,而不是接受System.Drawing.Bitmap的方法,以便为Silverlight版本的用户提供类似的功能集。

好的,让我们来看看为了创建.NET库的Silverlight版本可能需要做些什么。

  1. 为Silverlight版本
  2. 创建新项目
  3. 将所有现有代码文件添加到此项目作为链接
  4. 尝试构建项目。很可能构建将失败,并带有许多警告和错误消息。显然,目标是解决所有问题。
  5. 以下是一些可以解决常见构建错误的提示。

    1. 删除所有不需要的using namespace-name指令。使用条件编译排除不受支持的命名空间,如下所示:
    2. #if !SILVERLIGHT
          using System.Drawing;
      #endif
      
      1. 如果您使用的是Silverlight中缺少的枚举(例如System.Drawing.Imaging.ImageFormat),则引入等价的自定义枚举(例如MyImageFormat)并更改内部代码以仅使用自定义枚举。如果需要,将使用自定义枚举(或等效的Silverlight枚举)的重载方法添加到公共接口。

      2. 同样对结构(例如System.Drawing.PointF)或更改代码以使用更简单的类型(例如两个float而不是PointF结构)

        < / LI>
      3. 排除使用条件编译的不受支持的结构的公共和私有代码。考虑重写内部代码,使其仅使用.NET和Silverlight支持的语言结构。

      4. 创建一个包装类,用于访问Silverlight版本中的嵌入式资源,因为没有任何现成的包装器可以为您提供byte[]string二进制和文本资源。

      5. 创建一个这样的属性

      6.     public static Encoding DefaultEncoding
            {
                get
                {
            #if SILVERLIGHT
                    return Encoding.UTF8;
            #else
                    return Encoding.Default;
            #endif
                }
            }
        

        在代码中使用此属性而不是Encoding.Default

        迟早您将能够创建代码的Silverlight版本。这个版本可能会有更少的功能,但是,嘿,Silverlight并不是一个完整的.NET。 Silverlight中甚至不需要某些功能。对于某些原始功能,您稍后可能会添加相同的功能。

        如果您使用nunit对.NET版本进行单元测试,那么您可能需要查看nunit-silverlight(同时检查this page)以测试Silverlight版本。但是有一些警告。

        1. TestCaseSource属性不受nunit-silverlight支持。
        2. 不支持读取本地文件。
        3. 如果您需要在测试中读取或写入本地文件,那么您应该将Silverlight 4用于测试应用程序。在Silverlight 3中无法执行此操作。您还应将测试应用程序设置为浏览器外的一个并为其提供提升的信任权限(在浏览器外设置中选中“需要提升的信任”)

          您需要一个包装器(是的,另一个)来读取和写入本地文件,因为Silverlight测试将能够使用并仅生成字节缓冲区和流。

          以下是一些可能对包装器有用的代码片段:

          获取当前文件夹的路径:

          Uri uri = new Uri(System.Windows.Application.Current.Host.Source, relativeFileName);
          var currentPath = uri.OriginalString;
          

          请注意,您需要从file://开头删除currentPath

          读取本地文件(通过COM自动化)

          private static byte[] readBinaryFile(string fileName)
          {
              const int adTypeBinary = 1;
          
              using (dynamic adoCom = System.Runtime.InteropServices.Automation.AutomationFactory.CreateObject(@"ADODB.Stream"))
              {
                  adoCom.Type = adTypeBinary;
                  adoCom.Open();
                  adoCom.LoadFromFile(fileName);
          
                  return adoCom.Read();
              }
          }
          

          编写本地文件(也通过COM Automation)

          private static void writeBinaryFile(string fileName, byte[] binaryArray)
          {
              const int adTypeBinary = 1;
              const int adSaveCreateOverWrite = 2;
              using (dynamic adoCom = System.Runtime.InteropServices.Automation.AutomationFactory.CreateObject(@"ADODB.Stream"))
              {
                  adoCom.Type = adTypeBinary;
                  adoCom.Open();
                  adoCom.Write(binaryArray);
                  adoCom.SaveToFile(fileName, adSaveCreateOverWrite);
              }
          }
          

          您可能还想查看Silverlight COM Toolkit。不过我不会用它。

          祝你好运!