【问题标题】:XML to XAML transformation using XSLT 1.0 | Exclude specific transformations for some controls使用 XSLT 1.0 进行 XML 到 XAML 的转换 |排除某些控件的特定转换
【发布时间】:2013-02-27 15:26:21
【问题描述】:

假设我有以下 XML 代码

<PanelWrapper   id="RootPanel" 
                width="800" 
                height="600" 
                forecolor="Black">
    <ButtonWrapper  id="button" 
                    text="click!" 
                    forecolor="Black">
        <TabIndex>0</TabIndex>
        <TabStop>True</TabStop>
    </ButtonWrapper>
</PanelWrapper>

此代码应使用 XSLT 1.0 转换为 XAML 代码:

<WrapPanel Name="RootPanel" 
           Width="800" 
           Height="600">
    <Button Name="button" 
            Content="click!" 
            Foreground="Black"  
            TabIndex="0" 
            IsTabStop="True">
    </Button>
</WrapPanel>

我目前正在使用这个样式表:(简化版)

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>

    <!-- Transform PanelWrapper to WrapPannel -->
    <xsl:template match="PanelWrapper">
        <WrapPanel>
            <xsl:apply-templates select="@*|*" />
        </WrapPanel>
    </xsl:template>

    <!-- Transform ButtonWrapper to Button -->
    <xsl:template match="ButtonWrapper">
        <Button>
            <xsl:apply-templates select="@*" />
        </Button>
    </xsl:template>

    <!-- some other mapping for id(name), height, weight, text -->

    <!-- Map forecolor to Foreground -->
    <xsl:template match="@forecolor">
        <xsl:attribute name="Foreground">
            <xsl:value-of select="." />
        </xsl:attribute>
    </xsl:template>

</xsl:stylesheet>

我目前得到的结果是这样的:

<WrapPanel Name="RootPanel" 
           Width="800" 
           Height="600"
           Foreground="Black"> //unwanted, Problem 1
    <Button Name="button" 
            Content="click!" 
            Foreground="Black">
    </Button>
            0 //Problem 2
        True //Problem 2
</WrapPanel>

问题 1: XAML 中的 WrapPanel 没有 Foreground 属性,但由于在我的 XML 源文件中定义了前景色,因此它也是为 WrapPanel 生成的。我该如何解决这个问题?

问题 2: 如何解决 TabIndex 和 IsTabStop 的问题?

编辑:让我澄清问题 2。 这是 xml 输入:

<ButtonWrapper  id="button" 
                text="click!" 
                forecolor="Black">
    <TabIndex>0</TabIndex>
    <TabStop>True</TabStop>
</ButtonWrapper>

这是我试图实现的输出:

<Button Name="button" 
        Content="click!" 
        Foreground="Black"  
        TabIndex="0" 
        IsTabStop="True">
</Button>

【问题讨论】:

    标签: c# xaml xslt xslt-1.0 xsl-stylesheet


    【解决方案1】:

    问题 1。您可以添加以下模板

    <xsl:template match="PanelWrapper/@forecolor" />
    

    这将为所有 PanelWrapper 元素排除名为 forecolor 的属性。

    问题 2。要解决您的第二个问题,您必须分别使用以下 XPath 表达式匹配作为某个元素的子元素的所有 TabIndex 元素和 TabStop 元素:*/TabIndex、*/TabStop。然后你可以将该元素映射到一个属性。

    下面的转换实现了你想要的:

    <!-- Transform element TabIndex to an attribute with the same
         name in its parent -->
    <xsl:template match="*/TabIndex">
        <xsl:attribute name="TabIndex">
            <xsl:value-of select="." />
        </xsl:attribute>
    </xsl:template>
    
    <!-- Transform element TabStop to an attribute with the name
         IsTabStop in its parent -->
    <xsl:template match="*/TabStop">
        <xsl:attribute name="IsTabStop">
            <xsl:value-of select="." />
        </xsl:attribute>
    </xsl:template>
    

    更新。添加了完整 XML 的解决方案。

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
        <!-- special thanks to: Pablo Pozo -->
    
        <xsl:variable name="attributeMap"
                      select="'|font-size,FontSize|font-name,FontFamily|enabled,isEnabled|forecolor,Foreground|id,name|TabStop,IsTabStop|TabIndex,isTabIndex|dock,DockPanel.Dock|width,Width|height,Height|'" />
    
        <!--                        -->
        <!-- Default processing     -->
        <!--                        -->
    
        <!-- Ignore attributes by default, so we can have more control
             about unhandled attributes -->
        <xsl:template match="@*|*" />
        <xsl:template match="node()|@*" mode="to-attr"/>
    
        <!-- Default attribute processing -->
        <xsl:template name="process-element">
            <xsl:param name="attr" />
    
            <!-- Process all attributes and elements which are going to be
                 transformed to attributes -->
            <xsl:apply-templates select="@*|*" mode="to-attr" />
            <!-- Add extra attribute -->
            <xsl:if test="$attr">
                <xsl:attribute name="{substring-after($attr, '|')}">
                    <xsl:value-of select="@*[local-name() = substring-before($attr, '|')]" />
                </xsl:attribute>
            </xsl:if>
            <!-- Process children elements -->
            <xsl:apply-templates select="*" />
        </xsl:template>
    
        <!--                        -->
        <!-- Control transformations-->
        <!--                        -->
    
        <!-- Transform PanelWrapper to WrapPannel -->
        <xsl:template match="PanelWrapper">
            <WrapPanel>
                <xsl:call-template name="process-element" />
            </WrapPanel>
        </xsl:template>
    
        <!-- Exclude attributes for PanelWrapper -->
        <xsl:template match="PanelWrapper/@forecolor|PanelWrapper/@font-name|PanelWrapper/@font-size|PanelWrapper/@font-style"
                      mode="to-attr" />
        <!-- TODO: Exclude doesn't work for the following attributes -->
        <xsl:template match="PanelWrapper/@border-left|PanelWrapper/@border-top|PanelWrapper/@border-right|PanelWrapper/@border-bottom"
                      mode="to-attr"  />
    
        <!-- Transform DropDownWrapper to ComboBox -->
        <xsl:template match="DropDownWrapper">
            <ComboBox>
                <xsl:call-template name="process-element">
                    <xsl:with-param name="attr" select="'text|Text'" />
                </xsl:call-template>
            </ComboBox>
        </xsl:template>
    
        <!-- Exclude attributes for ComboBox -->
        <!-- Transform GroupBoxWrapper to GroupBox -->
    
        <!-- Map GroupBoxWrapper, LabelWrapper, TextBoxWrapper, ButtonWrapper into
             elements with their prefix as their name -->
        <xsl:template match="GroupBoxWrapper|LabelWrapper|TextBoxWrapper|ButtonWrapper">
            <xsl:element name="{substring-before(local-name(), 'Wrapper')}">
                <xsl:call-template name="process-element">
                    <xsl:with-param name="attr" select="'text|Content'" />
                </xsl:call-template>
            </xsl:element>
        </xsl:template>
    
        <!-- Exclude attributes for GroupBox -->
        <!-- Exclude attributes for Label -->
        <!-- Exclude attributes for Text -->
        <!-- TODO: invalid value for Background attribute, eg: Background="window" -->
        <!-- Exclude attributes for Button -->
        <!-- TODO: invalid value for Background attribute, eg: Background="buttonface" -->
    
    
        <!-- Map RadioButtonViewWrapper, CheckBoxViewWrapper into elements
             with their prefix as their name -->
        <xsl:template match="RadioButtonViewWrapper|CheckBoxViewWrapper">
            <xsl:element name="{substring-before(local-name(), 'ViewWrapper')}">
                <xsl:call-template name="process-element">
                    <xsl:with-param name="attr" select="'text|Content'" />
                </xsl:call-template>
            </xsl:element>
        </xsl:template>
    
    
        <!-- Exclude attributes for RadioButton -->
        <!-- Exclude attributes for CheckBox -->
    
    
        <!--                           -->
        <!-- Attributes transformations-->
        <!--                           -->
    
        <!-- Transform elements which just map the name of the attribute to a different name -->
        <xsl:template match="@font-size|@font-name|@enabled|@forecolor|@id|TabStop|TabIndex|@dock|@width|@height"
                      mode="to-attr">
            <!-- Look in map for the transformation -->
            <xsl:variable name="new-attribute"
                          select="substring-before(substring-after($attributeMap, concat('|', local-name(), ',')), '|')" />
            <xsl:attribute name="{$new-attribute}">
                <xsl:value-of select="." />
            </xsl:attribute>
        </xsl:template>
    
        <!-- OVERRIDE!! Back color: not sure of the logic here.-->
        <xsl:template match="@backcolor" mode="to-attr">
            <xsl:attribute name="Background">Grey</xsl:attribute>
        </xsl:template>
    
        <!-- Ignore TabIndex and TabStop within PanelWrapper -->
        <xsl:template match="PanelWrapper/TabIndex|PanelWrapper/TabStop" mode="to-attr" />
    
        <!-- Map @dock = 'Fill' to @dock = 'Left, Right...etc' -->
        <xsl:template match="@dock[. = 'Fill']"  mode="to-attr" >
            <xsl:attribute name="DockPanel.Dock">
                <xsl:value-of select="'Left, Right, Top, Bottom'" />
            </xsl:attribute>
        </xsl:template>
    
        <!-- Map visible attribute to Visibility -->
        <xsl:template match="@visible[. = 'True']"  mode="to-attr" >
            <xsl:attribute name="Visibility">visible</xsl:attribute>
        </xsl:template>
    
        <xsl:template match="@visible[. = 'False']"  mode="to-attr" >
            <xsl:attribute name="Visibility">hidden</xsl:attribute>
        </xsl:template>
    
        <!-- Build the border attribute -->
        <xsl:template match="@*[starts-with(local-name(), 'border-')][1]"  mode="to-attr">
            <xsl:attribute name="BorderThickness">
                <!-- Print the border-elements in a comma separated list (non-defined attributes default
                     to zero) -->
                <xsl:call-template name="border-print" />
            </xsl:attribute>
        </xsl:template>
    
        <!-- Recursive template to group borders in BorderThickness -->
        <xsl:template name="border-print">
            <!-- Do not remove spaces in the next line! -->
            <xsl:param name="string" select="'left  top   right bottom'" />
            <xsl:param name="parent" select=".." />
            <xsl:param name="not-first" select="false()" />
    
            <xsl:if test="$string != ''">
                <!-- Obtain next direction -->
                <xsl:variable name="direction" select="normalize-space(substring($string, 1, 6))" />
                <xsl:variable name="attr" select="$parent/@*[local-name() = concat('border-', $direction)]" />
                <!-- Print comma if not the first element -->
                <xsl:if test="$not-first"><xsl:text>,</xsl:text></xsl:if>
                <!-- Print zero if the attribute cannot be found -->
                <xsl:choose>
                    <!-- Attribute found : print -->
                    <xsl:when test="$attr">
                        <xsl:value-of select="$attr" />
                    </xsl:when>
                    <!-- Attribute not found: print 0 -->
                    <xsl:otherwise>
                        <xsl:text>0</xsl:text>
                    </xsl:otherwise>
                </xsl:choose>
                <!-- Recurse -->
                <xsl:call-template name="border-print">
                    <xsl:with-param name="string" select="substring($string, 7)" />
                    <xsl:with-param name="parent" select="$parent" />
                    <xsl:with-param name="not-first" select="true()" />
                </xsl:call-template>
            </xsl:if>
    
        </xsl:template>
    
        <xsl:template match="@*" mode="print-border">
            <xsl:value-of select="concat(., ',')" />
        </xsl:template>
    
        <xsl:template match="@border-bottom" mode="print-border">
            <xsl:value-of select="." />
        </xsl:template>
    
        <!--
        <xsl:template match="@font-style[. = 'Regular']">
            <xsl:attribute name="FontStyle">Normal</xsl:attribute>
        </xsl:template>
        -->
        <!-- TODO: condition is invalid, chooses Italic for everything-->
        <xsl:template match="@font-style"  mode="to-attr">
            <xsl:choose>
                <xsl:when test="'Italic'">
                    <xsl:attribute name="FontStyle">Italic</xsl:attribute>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:attribute name="FontStyle">Normal</xsl:attribute>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
    
    </xsl:stylesheet>
    

    【讨论】:

    • 感谢您解决第一个问题。我想我没有很好地解释第二个问题。我希望在我上次编辑后它变得更加清晰。
    • 对不起,我很快就阅读了您的帖子,但我没有意识到您正在尝试将元素转换为属性。我更新了答案。
    • 您对问题 2 的回答导致未处理的 XslTransformException “在已添加文本、注释、pi 或子元素节点后,无法将属性和命名空间节点添加到父元素。”
    • 这可能发生在你身上,因为你留下了一些未处理的属性。您可以将此答案与上一个答案(我在编辑此帖子之前首先发布的那个)结合起来,或者发布您的整个代码,以便我可以看到问题出在哪里。
    【解决方案2】:

    问题 1:WrapPanels 仍然显示 BorderThickness [已解决]

    解决方案:仅对除 PanelWrapper 之外的所有元素调用模板。 (看条件)

      <xsl:template match="@*[starts-with(local-name(), 'border-')][1]"  mode="to-attr">
        <xsl:if test="not(parent::PanelWrapper)">
            <xsl:attribute name="BorderThickness">
              <!--Print the border-elements in a comma separated list (non-defined attributes default
                     to zero)-->
              <xsl:call-template name="border-print" />
            </xsl:attribute>
          </xsl:if>
      </xsl:template>
    

    问题 2:由于 WPF 中的组框只接受一个控件,我必须首先将所有属性包装到一个网格控件中。我以为没什么大不了的,但事实证明,groupbox 属性被添加到了网格控件中。

    来了(更新的)xsl 样式表:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <!-- very special thanks to: Pablo Pozo -->
      <xsl:variable name="attributeMap"
                    select="'|font-size,FontSize|font-name,FontFamily|enabled,isEnabled|forecolor,Foreground|id,Name|TabStop,IsTabStop|TabIndex,TabIndex|dock,DockPanel.Dock|width,Width|height,Height|'" />
    
      <!-- Ignore attributes by default, so we can have more control
             about unhandled attributes -->
      <xsl:template match="@*|*" />
      <xsl:template match="node()|@*" mode="to-attr"/>
    
      <!-- Default attribute processing -->
      <xsl:template name="process-element">
        <xsl:param name="attr" />
    
        <!-- Process all attributes and elements which are going to be
                 transformed to attributes -->
        <xsl:apply-templates select="@*|*" mode="to-attr" />
        <!-- Add extra attribute -->
        <xsl:if test="$attr">
          <xsl:attribute name="{substring-after($attr, '|')}">
            <xsl:value-of select="@*[local-name() = substring-before($attr, '|')]" />
          </xsl:attribute>
        </xsl:if>
        <!-- Process children elements -->
        <xsl:apply-templates select="*" />
      </xsl:template>
    
      <!-- Transform PanelWrapper to WrapPannel -->
      <xsl:template match="PanelWrapper">
        <WrapPanel>
          <xsl:call-template name="process-element" />
        </WrapPanel>
      </xsl:template>
    
      <!-- Exclude attributes for PanelWrapper -->
      <xsl:template match="PanelWrapper/@forecolor|PanelWrapper/@font-name|PanelWrapper/@font-size|PanelWrapper/@font-style" 
                    mode="to-attr" />
      <xsl:template match="PanelWrapper/@border-left|PanelWrapper/@border-top|PanelWrapper/@border-right|PanelWrapper/@border-bottom" 
                    mode="to-attr"  />
      <xsl:template match="PanelWrapper/TabIndex|PanelWrapper/TabStop" 
                    mode="to-attr" />
    
      <!-- Transform DropDownWrapper to ComboBox -->
      <xsl:template match="DropDownWrapper">
        <ComboBox>
          <xsl:call-template name="process-element">
            <xsl:with-param name="attr" select="'text|Text'" />
          </xsl:call-template>
        </ComboBox>
      </xsl:template>
    
      <!-- Map GroupBoxWrapper into
             elements with their prefix as their name -->
      <xsl:template match="GroupBoxWrapper">
        <xsl:element name="GroupBox">
          <Grid>
          <xsl:call-template name="process-element">
            <xsl:with-param name="attr"/>
          </xsl:call-template>
          </Grid>
        </xsl:element>
      </xsl:template>
    
      <!-- Map LabelWrapper, ButtonWrapper into
             elements with their prefix as their name -->
      <xsl:template match="LabelWrapper|ButtonWrapper">
        <xsl:element name="{substring-before(local-name(), 'Wrapper')}">
          <xsl:call-template name="process-element">
            <xsl:with-param name="attr" select="'text|Content'" />
          </xsl:call-template>
        </xsl:element>
      </xsl:template>
    
      <!-- Map TextBoxWrapper into
               elements with their prefix as their name -->
      <xsl:template match="TextBoxWrapper">
        <xsl:element name="{substring-before(local-name(), 'Wrapper')}">
          <xsl:call-template name="process-element">
            <xsl:with-param name="attr" select="'text|Text'" />
          </xsl:call-template>
        </xsl:element>
      </xsl:template>
    
      <!-- Map RadioButtonViewWrapper, CheckBoxViewWrapper into elements
             with their prefix as their name -->
      <xsl:template match="RadioButtonViewWrapper|CheckBoxViewWrapper">
        <xsl:element name="{substring-before(local-name(), 'ViewWrapper')}">
          <xsl:call-template name="process-element">
            <xsl:with-param name="attr" select="'text|Content'" />
          </xsl:call-template>
        </xsl:element>
      </xsl:template>
    
      <!--                           -->
      <!-- Attributes transformations-->
      <!--                           -->
    
      <!-- Transform elements which just map the name of the attribute to a different name -->
      <xsl:template match="@font-size|@font-name|@enabled|@forecolor|@id|TabStop|TabIndex|@width|@height"
                    mode="to-attr">
        <!-- Look in map for the transformation -->
        <xsl:variable name="new-attribute"
                      select="substring-before(substring-after($attributeMap, concat('|', local-name(), ',')), '|')" />
        <xsl:attribute name="{$new-attribute}">
          <xsl:value-of select="." />
        </xsl:attribute>
      </xsl:template>
    
      <!-- Transform dock element  -->
      <xsl:template match="@dock" mode="to-attr">
        <xsl:choose>
          <xsl:when test=". = 'Fill'">
            <xsl:attribute name="DockPanel.Dock">
              <xsl:value-of select="'Left, Right, Top, Bottom'" />
            </xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <xsl:if test=". != 'None'">
              <xsl:attribute name="DockPanel.Dock">
                <xsl:value-of select="." />
              </xsl:attribute>
            </xsl:if>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>
    
      <!-- Transform Visual Web GUI Colors to XAML conform values.-->
      <xsl:template match="@backcolor" mode="to-attr">
        <xsl:choose>
          <xsl:when test=". = 'buttonface'">
            <xsl:attribute name="Background">Azure</xsl:attribute>
          </xsl:when>
          <xsl:when test=". = 'window'">
            <xsl:attribute name="Background">Azure</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <xsl:attribute name="Background">
              <xsl:value-of select="." />
            </xsl:attribute>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>
    
      <!-- Map visible attribute to Visibility -->
      <xsl:template match="@visible[. = 'True']"  mode="to-attr" >
        <xsl:attribute name="Visibility">visible</xsl:attribute>
      </xsl:template>
    
      <xsl:template match="@visible[. = 'False']"  mode="to-attr" >
        <xsl:attribute name="Visibility">hidden</xsl:attribute>
      </xsl:template>
    
      <!-- Build the border attribute -->
      <xsl:template match="@*[starts-with(local-name(), 'border-')][1]"  mode="to-attr">
        <xsl:attribute name="BorderThickness">
          <!-- Print the border-elements in a comma separated list (non-defined attributes default
                     to zero) -->
          <xsl:call-template name="border-print" />
        </xsl:attribute>
      </xsl:template>
    
      <!-- Recursive template to group borders in BorderThickness -->
      <xsl:template name="border-print">
        <!-- Do not remove spaces in the next line! -->
        <xsl:param name="string" select="'left  top   right bottom'" />
        <xsl:param name="parent" select=".." />
        <xsl:param name="not-first" select="false()" />
    
        <xsl:if test="$string != ''">
          <!-- Obtain next direction -->
          <xsl:variable name="direction" select="normalize-space(substring($string, 1, 6))" />
          <xsl:variable name="attr" select="$parent/@*[local-name() = concat('border-', $direction)]" />
          <!-- Print comma if not the first element -->
          <xsl:if test="$not-first">
            <xsl:text>,</xsl:text>
          </xsl:if>
          <!-- Print zero if the attribute cannot be found -->
          <xsl:choose>
            <!-- Attribute found : print -->
            <xsl:when test="$attr">
              <xsl:value-of select="$attr" />
            </xsl:when>
            <!-- Attribute not found: print 0 -->
            <xsl:otherwise>
              <xsl:text>0</xsl:text>
            </xsl:otherwise>
          </xsl:choose>
          <!-- Recurse -->
          <xsl:call-template name="border-print">
            <xsl:with-param name="string" select="substring($string, 7)" />
            <xsl:with-param name="parent" select="$parent" />
            <xsl:with-param name="not-first" select="true()" />
          </xsl:call-template>
        </xsl:if>
    
      </xsl:template>
    
      <xsl:template match="@*" mode="print-border">
        <xsl:value-of select="concat(., ',')" />
      </xsl:template>
    
      <xsl:template match="@border-bottom" mode="print-border">
        <xsl:value-of select="." />
      </xsl:template>
    
      <!-- Mapping font-style to FontStyle -->
      <!-- Convert values to valid XAML values -->
      <xsl:template match="@font-style">
        <xsl:choose>
          <xsl:when test=". = 'Italic'">
            <xsl:attribute name="FontStyle">Italic</xsl:attribute>
          </xsl:when>
          <xsl:otherwise>
            <xsl:attribute name="FontStyle">Normal</xsl:attribute>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:template>
    
    </xsl:stylesheet>
    

    这里是需要转换成xaml代码的xml文件

    <PanelWrapper id="RootPanel" dock="Fill" text="" theme="" width="1412" height="605" backcolor="Transparent" forecolor="Black" visible="True" mapNode="" border-left="0" border-top="0" border-right="0" border-bottom="0" font-name="Tahoma" font-size="8,25" font-style="Regular">
      <PanelWrapper id="panel1" dock="None" text="" theme="" width="800" height="400" backcolor="Transparent" forecolor="Black" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Regular">
        <GroupBoxWrapper id="groupbox1" dock="Bottom" text="" theme="" width="796" height="300" backcolor="Transparent" forecolor="#0046D5" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Regular">
          <RadioButtonViewWrapper id="radiobutton1" dock="Top" text="radiobox" theme="" width="484" height="100" backcolor="Transparent" forecolor="Black" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Regular">
            <TabIndex>1</TabIndex>
            <TabStop>True</TabStop>
          </RadioButtonViewWrapper>
          <CheckBoxViewWrapper id="checkbox1" dock="Left" text="checkbox" theme="" width="75" height="177" backcolor="Transparent" forecolor="Black" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Regular">
            <TabIndex>2</TabIndex>
            <TabStop>True</TabStop>
          </CheckBoxViewWrapper>
          <TabIndex>4</TabIndex>
          <TabStop>False</TabStop>
        </GroupBoxWrapper>
        <PanelWrapper id="panel5" dock="Top" text="Click!" theme="" width="796" height="25" backcolor="Transparent" forecolor="Black" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Regular">
          <ButtonWrapper id="button2" dock="Left" text="click!" theme="" width="100" height="21" backcolor="buttonface" forecolor="Black" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Regular">
            <TabIndex>0</TabIndex>
            <TabStop>True</TabStop>
          </ButtonWrapper>
          <TextBoxWrapper id="textbox2" dock="Left" text="textbox" theme="" width="100" height="21" backcolor="window" forecolor="Black" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Italic">
            <TabIndex>1</TabIndex>
            <TabStop>True</TabStop>
          </TextBoxWrapper>
          <LabelWrapper id="label2" dock="Left" text="label" theme="" width="100" height="21" backcolor="Transparent" forecolor="Black" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Regular">
            <TabIndex>2</TabIndex>
            <TabStop>False</TabStop>
          </LabelWrapper>
          <DropDownWrapper id="combobox2" dock="Left" text="combobox" theme="" width="100" height="21" backcolor="window" forecolor="Black" visible="True" mapNode="" border-left="1" border-top="1" border-right="1" border-bottom="1" font-name="Tahoma" font-size="9" font-style="Regular">
            <TabIndex>3</TabIndex>
            <TabStop>True</TabStop>
          </DropDownWrapper>
          <TabIndex>5</TabIndex>
          <TabStop>False</TabStop>
        </PanelWrapper>
        <TabIndex>0</TabIndex>
        <TabStop>False</TabStop>
      </PanelWrapper>
      <TabIndex>0</TabIndex>
      <TabStop>False</TabStop>
    </PanelWrapper>
    

    XAML 结果如下所示:

    <WrapPanel Name="RootPanel" DockPanel.Dock="Left, Right, Top, Bottom" Width="1412" Height="605" Background="Transparent" Visibility="visible" BorderThickness="0,0,0,0">
      <WrapPanel Name="panel1" Width="800" Height="400" Background="Transparent" Visibility="visible" BorderThickness="1,1,1,1">
        <GroupBox>
          <Grid Name="groupbox1" DockPanel.Dock="Bottom" Width="796" Height="300" Background="Transparent" Foreground="#0046D5" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="4" IsTabStop="False">
            <RadioButton Name="radiobutton1" DockPanel.Dock="Top" Width="484" Height="100" Background="Transparent" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="1" IsTabStop="True" Content="radiobox" />
            <CheckBox Name="checkbox1" DockPanel.Dock="Left" Width="75" Height="177" Background="Transparent" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="2" IsTabStop="True" Content="checkbox" />
          </Grid>
        </GroupBox>
        <WrapPanel Name="panel5" DockPanel.Dock="Top" Width="796" Height="25" Background="Transparent" Visibility="visible" BorderThickness="1,1,1,1">
          <Button Name="button2" DockPanel.Dock="Left" Width="100" Height="21" Background="Azure" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="0" IsTabStop="True" Content="click!" />
          <TextBox Name="textbox2" DockPanel.Dock="Left" Width="100" Height="21" Background="Azure" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="1" IsTabStop="True" Text="textbox" />
          <Label Name="label2" DockPanel.Dock="Left" Width="100" Height="21" Background="Transparent" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="2" IsTabStop="False" Content="label" />
          <ComboBox Name="combobox2" DockPanel.Dock="Left" Width="100" Height="21" Background="Azure" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="3" IsTabStop="True" Text="combobox" />
        </WrapPanel>
      </WrapPanel>
    </WrapPanel>
    

    预期的 XAML 代码应如下所示:

    <WrapPanel Name="RootPanel" DockPanel.Dock="Left, Right, Top, Bottom" Width="1412" Height="605" Background="Transparent" Visibility="visible" >
        <WrapPanel Name="panel1" Width="800" Height="400" Background="Transparent" Visibility="visible" >
            <GroupBox Name="groupbox1" DockPanel.Dock="Bottom" Width="796" Height="300" Background="Transparent" Foreground="#0046D5" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="4" IsTabStop="False">
                <Grid>
                    <RadioButton Name="radiobutton1" DockPanel.Dock="Top" Width="484" Height="100" Background="Transparent" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="1" IsTabStop="True" Content="radiobox" />
                    <CheckBox Name="checkbox1" DockPanel.Dock="Left" Width="75" Height="177" Background="Transparent" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="2" IsTabStop="True" Content="checkbox" />
                </Grid>
            </GroupBox>
            <WrapPanel Name="panel5" DockPanel.Dock="Top" Width="796" Height="25" Background="Transparent" Visibility="visible" >
                <Button Name="button2" DockPanel.Dock="Left" Width="100" Height="21" Background="Azure" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="0" IsTabStop="True" Content="click!" />
                <TextBox Name="textbox2" DockPanel.Dock="Left" Width="100" Height="21" Background="Azure" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="1" IsTabStop="True" Text="textbox" />
                <Label Name="label2" DockPanel.Dock="Left" Width="100" Height="21" Background="Transparent" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="2" IsTabStop="False" Content="label" />
                <ComboBox Name="combobox2" DockPanel.Dock="Left" Width="100" Height="21" Background="Azure" Foreground="Black" Visibility="visible" BorderThickness="1,1,1,1" FontFamily="Tahoma" FontSize="9" TabIndex="3" IsTabStop="True" Text="combobox" />
            </WrapPanel>
        </WrapPanel>
    </WrapPanel>
    

    顺便说一句:Pablo Pozo,我至少欠你两杯啤酒

    【讨论】:

    • 一个问题:WrapPanel 元素必须忽略 TabIndex 和 TabStop 元素?
    • 我已经用完整的 XML 更新了我的解决方案。我使用了几种技术来减小文件大小(减少了大约 100 行),但是我没有时间解释这些技术。查看我发布的来源,如果您在理解我所做的事情时遇到困难,请问我(但我恐怕要等到 4 小时或更长时间后我才能回答您)。
    • 唯一与您的输出不同的是 FontStyle = 'Normal',但我认为根据您的代码上的最后一个模板,它可以按预期工作。
    • 谢谢你,你的帖子很有帮助!我更新了上一篇文章以解决两个问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多