12

我刚刚完成了一个 Silverlight 项目,是时候进行一些清理工作了。我想将我的核心文件放入一个单独的项目中,我将从我的主 Silverlight 应用程序中引用该项目。其中一些类与 WPF 兼容,我非常希望能够在一个项目中包含 Silverlight / WPF 代码。我理想的解决方案是允许多个配置的单个项目。所以,

配置:Silverlight 将生成:Company.Controls.Silverlight.dll

配置:WPF 会生成:Company.Controls.Wpf.dll

是否可以在通过定义分隔的同一个文件中具有相同的源?

有没有人这样做过?

编辑:我为每个项目创建了一个解决方案,例如 MyCompany.Windows.Controls,然后包含 2 个项目,MyCompany.Windows.Controls 和 MyCompany.Windows.Controls.Silverlight。除了这两个文件夹之外,我还有一个“共享”文件夹,其中包含两个项目使用的文件。到目前为止效果很好:)

4

3 回答 3

10

更新:表明几乎总是有更简单的方法。:-)

第一步是使用条件编译来隔离 Silverlight 特定的代码。(我假设您的“默认”目标是 WPF。)

其次,您需要一个构建脚本来为每个平台编译代码,设置适当的定义和程序集引用。

看看开源的Caliburn 项目。它做到了这一切。

这是 Caliburn 的 ExtensionMethods 类中的一个示例。

    public static T GetResource<T>(this FrameworkElement element, object key)
        {
            DependencyObject currentElement = element;

            while (currentElement != null)
            {
                var frameworkElement = currentElement as FrameworkElement;

                if (frameworkElement != null && frameworkElement.Resources.Contains(key))
                    return (T)frameworkElement.Resources[key];

#if !SILVERLIGHT
                currentElement = (LogicalTreeHelper.GetParent(currentElement) ??
                    VisualTreeHelper.GetParent(currentElement));
#else
                currentElement = VisualTreeHelper.GetParent(currentElement);
#endif
            }

            if (Application.Current.Resources.Contains(key))
                return (T)Application.Current.Resources[key];

            return default(T);
        }

如果您在 VS 中打开 Caliburn 并对其进行编译,则它符合标准框架。这些参考适用于 .NET 3.5 和 WPF,而不是 Silverlight。这也是预处理指令是“!SILVERLIGHT”的原因。

在您的构建脚本(Caliburn 使用 NAnt)中,您将有一个为每个平台设置定义的目标,例如,Caliburn 的 Silverlight 目标是:

<target name="config-platform-silverlight20">
    <property name="nant.settings.currentframework" value="silverlight-2.0"/>
    <property name="build.platform" value="silverlight-2.0"/>
    <property name="build.defines" value="${global.build.defines},SILVERLIGHT,SILVERLIGHT_20,NO_WEB,NO_REMOTING,NO_CONVERT,NO_PARTIAL_TRUST,NO_EXCEPTION_SERIALIZATION,NO_SKIP_VISIBILITY,NO_DEBUG_SYMBOLS"/>
    <property name="current.path.bin" value="${path.bin}/silverlight-2.0/${build.config}"/>
    <property name="current.path.test" value="${path.bin}/silverlight-2.0/tests" />
    <property name="current.path.lib" value="${path.lib}/Silverlight" />
</target>

然后是调用实际 Silverlight 构建的目标:

<target name="platform-silverlight20" depends="config">
    <if test="${framework::exists('silverlight-2.0')}">
        <echo message="Building Caliburn ${build.version} for Silverlight v2.0."/>
        <call target="config-platform-silverlight20"/>
        <copy todir="${current.path.bin}">
            <fileset basedir="${current.path.lib}">
                <include name="*.dll"/>
                <include name="*.xml"/>
            </fileset>
        </copy>
        <call target="core"/>
        <call target="messaging"/>
        <call target="actions"/>
        <call target="commands"/>
        <call target="package-platform"/>
    </if>
    <if test="${not(framework::exists('silverlight-2.0'))}">
        <echo message="Silverlight v2.0 is not available. Skipping platform."/>
    </if>
</target>

最后,这是一个负责生成 Caliburn.Core.dll 的“核心”目标示例:

<target name="core" depends="config, ensure-platform-selected">
    <mkdir dir="${current.path.bin}"/>
    <csc keyfile="${path.src}/Caliburn.snk" noconfig="true" warnaserror="false" target="library" debug="${build.debug}" optimize="${build.optimize}" define="${build.defines}"
     output="${current.path.bin}/Caliburn.Core.dll"
     doc="${current.path.bin}/Caliburn.Core.xml">
        <sources basedir="${path.src}">
            <include name="${build.asminfo}"/>
            <include name="Caliburn.Core/**/*.cs"/>
        </sources>
        <references basedir="${current.path.bin}">
            <include name="mscorlib.dll"/>
            <include name="System.dll"/>
            <include name="System.Core.dll"/>
            <!--WPF-->
            <include name="PresentationCore.dll"/>
            <include name="PresentationFramework.dll"/>
            <include name="WindowsBase.dll"/>
            <!--Silverlight-->
            <include name="System.Windows.dll" />
        </references>
        <nowarn>
            <warning number="1584"/>
        </nowarn>
    </csc>
</target>

注意它引用必要程序集的方式。

You'll probably need to edit your NAnt.exe.config (if you are using NAnt) to match the correct version of the Silverlight framework. For Silverlight RTW, the framework version will be 2.0.31005.0.

于 2008-10-16T21:22:36.660 回答
6

I haven't tried it myself (still trying to find the time to play with Silverlight), but couldn't you have one solution with two projects, one targetting Silverlight and the other targetting .NET 3.5, and add the common class files to each project as Links (right-click the project, Add Existing Item..., Add as Link)?

** Update: See Mark's answer below regarding the Project Linker. I've been using this in my multi-targetted composite application with the PRISM 2.0 CAL and it's a beautiful thing. I don't think this existed in PRISM 1.0?

于 2008-10-17T02:57:02.727 回答
3

You should check out "patterns & practices: Composite WPF and Silverlight"

http://www.codeplex.com/CompositeWPF/Wiki/View.aspx?title=Home

It has quick starts with WPF/Silvelight versions of the same app in one solution. Also a "Project Linker" that updates the source of your WPF app when you change Silverlight code (or vice versa) using linking. It can be overridden when you have version specific code.

The examples are still a little rough around the edges but it may give you an idea of how to go about your project.

HTH

于 2008-11-12T23:17:17.827 回答