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

发布于 2024-10-06 13:15:49 字数 215 浏览 1 评论 0原文

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

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

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

更新:该代码是一个非可视组件。不是应用程序。没有第 3 方依赖项。

We have pretty much C# 2.0 code that heavily relies on System.Drawing namespace. Also there is some WinGDI dependencies (via interop).

How would you recommend to tackle the problem of making functionally equivalent Silverlight version of the code? We want to reuse code as much as possible because we want to continue develop both versions of the code.

Maybe there is some articles/books you could recommend?

UPDATE: The code is a non-visual component. Not an application. There is no 3rd party dependencies.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

三生殊途 2024-10-13 13:15:49

我在创建过去使用 winforms 构建的软件的 wpf/silverlight 版本方面拥有丰富的经验。这很可悲,但就你而言,当你使用大量互操作和 System.Drawing 东西时,实际上不可能做这样的事情。

当然,您总是可以尝试(实际上您总是必须)将业务逻辑与界面分开,但在这种情况下(我希望是错误的!),由于架构的差异,您的界面必须完全重新设计winforms 和 wpf/silverlight。

根据我的经验,这个问题是这样解决的:所有旧的 winforms 组件都保持不变,但所有新功能都是使用 wpf 构建的,并将 wpf 控件注入到 winforms 应用程序中。

是的,有时这很奇怪,但它确实比浪费所有旧代码并花费大量时间和金钱到新代码上更有效率,效果是一样的。

I have a great experience in creating wpf/silverlight versions of software that used to be built using winforms. It's sad, but in your case, when you use a lot of interop and System.Drawing things, it's practically impossible to do such a thing.

Of cource, you can always try (and really you always have to) to separate your business logic from interface, but in such situation (I hope a'm wrong!), your interface have to be completely redesigned, because of differences in architecture of winforms and wpf/silverlight.

In my experience, this problem solved in this way: all old winforms components stayed just the same, but all new features were built using wpf with help of injection of wpf controls into winforms application.

Yes, sometimes it's weird, but it's really more productive than just waste all your old code and spend huge amount of time and money into new, that does just the same.

一念一轮回 2024-10-13 13:15:49

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

如果是这样的话,由于移植所有代码的成本非常高,如果可能的话,你可以考虑改变你的架构。

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

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

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

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

上述组件的另一种替代方案是您自己将该组件托管在服务器上或某些公共云(例如 Windows Azure)上。

If there is no GUI and you are still using lots of System.Drawing I guess what this component does is related to manipualtion of images in memory.

If that's the case, due to the very high cost of porting all the code, if at all possible, you can consider to change your architecture.

Have the old code in the server side, where you can freely use these APIs, and expose the required functionality to your Silverlight application through some web service. If the component has no GUI it should be very feasible.

Edit: Adding suggestions of how this might be appropriate for developers

Maybe this might still work - if your developer plans to deploy this Silverlight control in a web page, then he probably has a web server on which he can place your component to be accessible for the Silverlight code.

If the developer plans to deploy your Silverlight code in Out-of-Browser mode, you can make a version that would embed the old component (for example as a COM object).

An addition alternative to the above, would be to host this component yourself on a server, or on some public cloud such as Windows Azure.

梦里兽 2024-10-13 13:15:49

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

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

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

可能不是您正在寻找的答案。

This is going to be near impossible as both WPF and Silverlight are fundamentally different than older versions of this. If you really want to be able to develop a desktop and web applications at the same time, you would probably be better off using WPF and Silverlight.

Only problem this is reusing code is still difficult because Silverlight doesn't have all of the features that WPF does. On top of all of this, the model for accessing data in Silverlight is totally asynchronous.

You would be best off building the application in Silverlight, and then porting that application to WPF.

Probably not the answer you were looking for.

童话 2024-10-13 13:15:49

根据现有代码库的架构方式,这可能是不可能的,但您可以在 WPF 内部加载 Forms 控件,请参阅 这个例子。如果你的遗留代码被打包到控件中,你也许能够得到大量的代码重用。我希望这有帮助。

Depending on how your existing code base is architected this may not be possible, but you can load Forms controls inside of WPF see this example. If your legacy code is packaged into controls, you may be able to get a lot of code re-use. I hope this helps.

若无相欠,怎会相见 2024-10-13 13:15:49

这是另一个疯狂的想法。

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

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

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

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

Here's another wild idea.

Isolate all your System.Drawing, PInvoke, GDI, etc. into a separate component, and wrap it as an ActiveX object.

Embed the ActiveX object in your web page, and make your Silverlight application consume its services somehow. I guess this would require some "plumbing" in the level of the web page (e.g. a script that would activate the ActiveX object, and expose the results to the Silverlight app through the document or something)

This is just an initial thought I had. I guess it can be improved in many ways. What do you think? :)

Edit: If it is acceptable for your Silverlight code to run in Out-of-Browser mode, then Silverlight 4 supports embedding an ActiveX control in your Silverlight application. This just might make it feasible to wrap all your old implementation in some ActiveX and use it from Silverlight.

土豪 2024-10-13 13:15:49

首先,您应该接受原始代码的某些功能不会出现在 Silverlight 版本中。互操作、读写文件——这些事情要么因为安全原因而被禁止,要么只是不受支持。

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

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

好的,让我们看看您可能需要执行哪些操作才能创建 Silverlight 版本的 .NET 库。

  1. 为 Silverlight 版本创建新项目
  2. 将所有现有代码文件作为链接添加到此项目。
  3. 尝试构建该项目。构建很可能会失败,并出现许多警告和错误消息。显然,我们的目标是解决所有问题。

以下是有关如何修复常见构建错误的一些提示。

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

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

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

  4. 创建一个包装器类来访问 Silverlight 版本中的嵌入式资源,因为不会有任何现成的包装器为您提供二进制和字符串的 byte[]string文本资源。

  5. 创建这样的属性

    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(查看 此页面 也用于测试 Silverlight 版本。不过,也有一些注意事项。

  1. nunit-silverlight 不支持 TestCaseSource 属性。
  2. 不支持读取本地文件。

如果您需要在测试中读取或写入本地文件,那么您应该在测试应用程序中使用 Silverlight 4。在 Silverlight 3 中无法执行此操作。您还应该将测试应用程序设置为浏览器外应用程序,并为其授予更高的信任权限(在浏览器外设置中选中“需要提升的信任”)

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

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

获取当前文件夹的路径:

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

请注意,您需要从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 自动化)

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 工具包。不过我不使用它。

祝你好运!

First of all, you should accept that some of the features of the original code won't make it to Silverlight version. Interop, reading and writing files - such things are either forbidden because of security reasons or just unsupported.

Second thing to have in mind is that your code will be polluted with conditional compilation (in case you want to continue to support building of .NET version from the same code base).

And the third thing is - you will have to write some new code (instead of removed code). For example, you might need to create new methods that accept WriteableBitmap instead of methods that accept System.Drawing.Bitmap in order to give users of Silverlight version similar set of features.

Ok, let's take a look at what you might need to do in order to create Silverlight version of a .NET library.

  1. Create new project for Silverlight version
  2. Add all existing code files to this project as links.
  3. Try to build the project. Most probably the build will fail with many warning and error messages. Obviously, the goal is to fix all of them.

Here is some hints for what can be done to fix common build errors.

  1. Remove all using namespace-name directives that are not needed. Exclude unsupported namespaces with conditional compilation like so:
#if !SILVERLIGHT
    using System.Drawing;
#endif
  1. If you are using enumerations that are missing in Silverlight (e.g. System.Drawing.Imaging.ImageFormat) then introduce equvalent custom enumerations (e.g. MyImageFormat) and change internal code to use only custom enumerations. Add overloaded methods that use custom enumerations (or equivalent Silverlight enumerations) to public interface, if needed.

  2. Do likewise for the structs (e.g. System.Drawing.PointF) or change the code to use simpler types (e.g. two floats instead of PointF structure)

  3. Exclude public and private code that uses unsupported structures with conditional compilation. Consider rewriting internal code so it will use only language constructs supported in .NET and Silverlight.

  4. Create a wrapper class for accessing embedded resources in Silverlight version because there won't be any ready-made wrappers that give you byte[] or string for binary and text resources.

  5. Create a property like this

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

And use this property instead of Encoding.Default in your code.

Sooner or later you will be able to create Silverlight version of your code. This version will probably have less features but, hey, Silverlight is not a full-blown .NET. Some features will even be unnecessary in Silverlight. For some original features you might later add equivalent ones.

If you are using nunit for unit-testing your .NET version then you might want to take a look at nunit-silverlight (check this page too) for testing Silverlight version. There are some caveats, though.

  1. TestCaseSource attribute is unsupported by nunit-silverlight.
  2. Reading of local files is unsupported.

If you need to read or write local files in your tests then you should use Silverlight 4 for your test application. There is no way to do this in Silverlight 3. You should also setup your test application as Out-of-Browser one and give it elevated trust rights (check "require elevated trust" in Out-of-Browser settings)

You'll need a wrapper (yeah, another one) for reading and writing local files, because Silverlight tests will be able to consume and produce only byte buffers and streams.

Here are some code snippets that might be useful for the wrapper:

Get the path to current folder:

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

Please note, that you'll need to remove file:// from the beginning of currentPath

Reading local files (via COM Automation)

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();
    }
}

Writing local files (also via 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);
    }
}

You may also want to check Silverlight COM Toolkit. I don't use it, though.

Good luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文