PropertyRef要求ComboBox

时间:2012-11-12 14:47:40

标签: combobox wix windows-installer

在我的一个对话框中,我有以下控件:

<Control Id="EnvironmentComboBox" Type="ComboBox" Sorted="yes" ComboList="yes" Property="ENVIRONMENT" X="25" Y="110" Width="200" Height="15" />

我在其他地方填写ComboBox:

<UI>
  <ComboBox Property="ENVIRONMENT">
    <ListItem Text="Development" Value="Development" />
    <ListItem Text="SIT" Value="SIT" />
    <ListItem Text="UAT" Value="UAT" />
    <ListItem Text="Production" Value="Production" />
  </ComboBox>
</UI>

但是,如果我没有创建ComboBox位,MSI仍将构建,并且在安装期间它将失败(2205)。因此,我想强制要求拥有一个名为ENVIRONMENT的属性。我已经尝试在我的对话框中添加如下所示的PropertyRef:

<PropertyRef Id="ENVIRONMENT" />

然而,这似乎没有拿起<ComboBox Proeprty="ENVIRONMENT">。它将获取一个常规属性(<Property Id="ENVIRONMENT" Value="test" />),但这并没有多大帮助。

有没有办法要求定义ComboBox

编辑:为了澄清,我打算将ComboBox定义与Control定义分开,以便可以重用该对话框。

3 个答案:

答案 0 :(得分:4)

MSI可以在没有为属性声明的Combobox项目的情况下存在,由元素引用(您可以在组合框文本字段中键入任何文本,以防ComboList =&#39; no& #39;)

* 该元素在MSI表格中没有任何相应的对象 * (只有它的子元素才会被写入MSI&#39 ; s ComboBox表)。所以我认为这个元素在WIX点是完全可选的。

您的错误#2205是由于&ComchaBox&#39;不存在而导致的。表格。我想安装程序中只有一个组合框。从理论上讲,不可能在编译时将其检测为错误(也可以在自定义操作中创建表)。 WIX团队可以做的最多就是生成警告。

为避免此错误,我在可重用项目中声明了一个虚拟组合框:

  <Fragment><!--This fragment is intended to fill MSI tables with dummy items so that these tables became created. Tables without items aren't created-->
    <UI Id="Dummy">
      <Dialog Id="DummyDlg" Width="370" Height="270" Title="Dummy" NoMinimize="yes">
        <Control Id="DummyDlgComboBox" Type="ComboBox" Property="DummyComboboxProperty" Width="200" Height="17" X="100" Y="80">
          <ComboBox Property="DummyComboboxProperty">
            <ListItem Text="Dummy" Value="Dummy" />
          </ComboBox>
        </Control>
      </Dialog>
    </UI>
  </Fragment>

并从常用的UI序列中引用此UI。

现在我不需要担心任何安装人员对组合框的存在感到担忧。

至于问题的解决方法 - 如何强制用户不要忘记声明列表项,我会做一个 tepmlate wix文件而不是wixlib 。像这样:

<Control Id="EnvironmentComboBox" Type="ComboBox" Sorted="yes" ComboList="yes" Property="ENVIRONMENT" X="25" Y="110" Width="200" Height="15">
  <ComboBox Property="ENVIRONMENT">
    <Placeholder Id="EnvironmentComboBoxItems" />
  </ComboBox>
</Combobox>

并为用户提供使用您提供的模板转换工具重用此代码的唯一功能。它将验证是否为所有模板占位符提供了内容。

转换可能如下所示:

<TemplateSubstitutions>
  <PlaceholderContent PlaceholderId='EnvironmentComboBoxItems'>
    <ListItem Text="Development" Value="Development" />
    <ListItem Text="SIT" Value="SIT" />
    <ListItem Text="UAT" Value="UAT" />
    <ListItem Text="Production" Value="Production" />
  </PlaceholderContent>
</TemplateSubstitutions>

合并它们的工具:

static void Main(string[] args)
{
    var templatePath = args[0];
    var templateTransformPath = args[1];
    var resultPath = args[2];

    var templateDoc = XDocument.Load(templatePath);
    var transformationDoc = XDocument.Parse(templateTransformPath);

    Dictionary<string, XElement> contents = transformationDoc.Element("TemplateSubstitutions").Elements("PlaceholderContent").ToDictionary(e => e.Attribute("PlaceholderId").Value, e => e);

    var planceHolders = templateDoc.Descendants("Placeholder").ToArray();
    foreach (var ph in planceHolders)
    {
        ph.ReplaceWith(new XElement(contents[ph.Attribute("Id").Value]).Nodes());
    }
    templateDoc.Save(resultPath);
}

当然这个工具尚未发布 - 您可能希望向客户端添加一些有意义的错误消息并验证提供的转换。但是为了避免代码复杂化,我没有实现它。

我在目前的几个安装程序项目中使用此方法。所有模板都存储在公共位置,客户端安装程序可以获取所需的任何文件并对其进行转换。

我的发布工具当然有点先进。它可以使用通配符替换属性中的值 - 我认为在重用组件时它非常有用。我使用这样的模板:

<Component Guid="{StrToGuid({ProductName}_7A51C3FD-CBE9-4EB1-8739-A8F45D46DCF5)}">

用户应在我的模板转换工具的命令行中提供所有模板属性(例如&#39; ProductName&#39;)。它确保组件在不同产品之间具有唯一的GUID,因此当它们安装在同一台机器上时不会发生冲突。

注意:请注意图括号 - 它们对WIX和MSI具有特殊含义:http://msdn.microsoft.com/library/aa368609.aspx。但对我来说还不够清楚,我不经常使用它们。但是您可能需要另一个通配符前缀。

至于组织安装程序构建过程,您可以在预构建项目时添加模板转换调用。但我决定使用单独的构建脚本而不是本机Visual Studio构建。它看起来更简单灵活。而且我不会得到像&#34;命令&#39; xxx&#39;退出代码yyy&#34; - 我总是看到模板转换日志,错误消息等。

希望我对车轮的改造能帮助任何人=)。

答案 1 :(得分:1)

我怀疑<PropertyRef>的设计方式只是选取属性的“直接”定义,即<Property>元素。 <ComboBox>只提及其属性中的属性名称,并且不会将其视为属性定义。

为您的示例添加“直接”属性定义,它应该有效:

<UI>
  <Property Name="ENVIRONMENT" Value="" />
  <ComboBox Property="ENVIRONMENT">
    <ListItem Text="Development" Value="Development" />
    <ListItem Text="SIT" Value="SIT" />
    <ListItem Text="UAT" Value="UAT" />
    <ListItem Text="Production" Value="Production" />
  </ComboBox>
</UI>

并在另一个地方用<PropertyRef>元素引用它 - 就像你尝试的那样。 据我所知,这样的定义不会损害组合框部分,并且您将安全地保留适当的片段包含。

或者,您可以使用<UI>元素引用整个<UIRef>元素 - 它应该具有相同的效果。

答案 2 :(得分:0)

为什么不在元素中定义你的组合框?像这样:

<Control Id="EnvironmentComboBox" Type="ComboBox" Sorted="yes" ComboList="yes" Property="ENVIRONMENT" X="25" Y="110" Width="200" Height="15">
  <ComboBox Property="ENVIRONMENT">
    <ListItem Text="Development" Value="Development" />
    <ListItem Text="SIT" Value="SIT" />
    <ListItem Text="UAT" Value="UAT" />
    <ListItem Text="Production" Value="Production" />
  </ComboBox>
</Combobox>

在这种情况下,您将无法引用不参考组合框的对话框。也许我理解你错了,但它看起来逻辑上是为了避免用户错误而不是抛弃它们。

如果您的用户需要能够更改库对话框的列表项,则可以使用自定义操作填充对话框项(例如,在静态值的情况下,这可能不是最佳方法)。

我还遇到了很多重复使用WIX元素的问题,最后创建了自己的模板项目,并使用了一些wxs文件的转换(现在非常简单,但可以实现我需要的任何东西)。效果很好,并提供无限的灵活性。