在一个项目中编译Silverlight和WPF的最佳实践是什么?

时间:2008-10-16 11:07:24

标签: wpf visual-studio-2008 silverlight assemblies

我刚刚完成了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。除了这两个文件夹,我还有一个“共享”文件夹,其中包含两个项目使用的文件。它到目前为止运作良好:)

3 个答案:

答案 0 :(得分:10)

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

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

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

看一下开源Caliburn project。它做到了这一切。

以下是来自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>

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

您可能需要编辑NAnt.exe.config(如果您使用的是NAnt)以匹配正确版本的Silverlight框架。对于Silverlight RTW,框架版本将为2.0.31005.0。

答案 1 :(得分:6)

我自己没有尝试过(仍然试图找时间玩Silverlight),但是你不能拥有一个带有两个项目的解决方案,一个针对Silverlight,另一个针对.NET 3.5,并添加常见的将每个项目的类文件作为链接(右键单击项目,添加现有项目...,添加为链接)?

**更新:请参阅Mark关于项目链接器的答案。我一直在使用PRISM 2.0 CAL的多目标复合应用程序中使用它,这是一件很棒的事情。我认为这不存在于PRISM 1.0中吗?

答案 2 :(得分:3)

你应该查看“模式和实践:复合WPF和Silverlight”

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

它可以在一个解决方案中快速启动相同应用程序的WPF / Silvelight版本。 还有一个“项目链接器”,当您使用链接更改Silverlight代码(反之亦然)时,它会更新WPF应用程序的源代码。如果您有特定于版本的代码,则可以覆盖它。

这些例子在边缘仍然有点粗糙,但它可以让你知道如何进行你的项目。

HTH