4

XML 構成によって駆動されるユーザー コントロールをセットアップしています。例で説明する方が簡単です。次の構成スニペットを見てください。

<node>
  <text lbl="Text:"/>
  <checkbox lbl="Check me:" checked="true"/>
</node>

そのスニペットを単一のテキストボックスとチェックボックスコントロールに変換するために私が達成しようとしていること。もちろん、スニペットに含まれるノードが多ければ、より多くのコントロールが自動的に生成されます。

タスクの反復的な性質を考慮して、私は Repeater を使用することにしました。その中に、2 つの (さらに詳しくは以下を参照) コントロール、1 つの CheckBox と 1 つの Editbox を配置しました。どのコントロールをアクティブにするかを選択するために、インライン スイッチ コマンドを使用して、現在の構成ノードの名前を確認しました。

残念ながら、それはうまくいきません。問題は、データ バインディングが発生してからずっと後、レンダリング時にスイッチが実行されているという事実にあります。それだけでは問題にはなりません。構成ノードが必要な情報をデータ バインドに提供する可能性があるという事実のためではありませんでした。チェック ボックス コントロールが上記のスニペットのテキスト ノードにバインドしようとし、その "checked" 属性を必死に探したらどうなるかを考えてみてください。

これを可能にする方法はありますか?

ありがとう、ボアズ

これが私の現在のコードです:

これが私のコードです(上記よりも複雑な構文で実行されます):

<asp:Repeater ID="settingRepeater" runat="server">
        <ItemTemplate>
           <% 
              switch (((XmlNode)Page.GetDataItem()).LocalName)
              {
                 case "text":
           %>
           <asp:Label ID="settingsLabel" CssClass="editlabel" Text='<%# XPath("@lbl") %>' runat="server" />
           <asp:TextBox ID="settingsLabelText" Text='<%# SettingsNode.SelectSingleNode(XPath("@xpath").ToString()).InnerText %>'
              runat="server" AutoPostBack="true"  Columns='<%#  XmlUtils.OptReadInt((XmlNode)Page.GetDataItem(),"@width",20) %>'
              />
           <% break;
                 case "checkbox":
           %>
           <asp:CheckBox ID="settingsCheckBox" Text='<%# XPath("@lbl") %>' runat="server"
                         Checked='<%# ((XmlElement)SettingsNode.SelectSingleNode(XPath("@xpath").ToString())).HasAttribute(XPath("@att").ToString()) %>'
            />
          <% break;
              } %>
           &nbsp;&nbsp;
        </ItemTemplate>
     </asp:Repeater>
4

2 に答える 2

4

ある週末の後、これが解決策として私が思いついたものです。私の主な目標は、機能し、アイテム テンプレートの正確なコンテンツをマークアップで指定し続けることができるものを見つけることでした。コードから何かを行うことは機能しますが、それでも面倒な場合があります。

コードは簡単に理解できるはずですが、問題の要点は 2 つの部分にあります。

1 つ目は、Repeater item created イベントを使用して、テンプレートの不要な部分を除外することです。

2 つ目は、ポストバック中にページを再作成するために、ViewState で行われた決定を保存することです。Item.DataItem を使用したことに気付くので、後者は非常に重要です。ポストバック中、コントロールの再作成はページ ライフ サイクルのかなり早い段階で行われます。ItemCreate が起動すると、DataItem は null になります。

これが私の解決策です:

制御マークアップ

 <asp:Repeater ID="settingRepeater" runat="server" 
            onitemcreated="settingRepeater_ItemCreated" 
          >
        <ItemTemplate>
             <asp:PlaceHolder  ID="text" runat="server">
                  <asp:Label ID="settingsLabel" CssClass="editlabel" Text='<%# XPath("@lbl") %>' runat="server" />
                  <asp:TextBox ID="settingsLabelText"  runat="server"
                      Text='<%# SettingsNode.SelectSingleNode(XPath("@xpath").ToString()).InnerText %>'
                     Columns='<%#  XmlUtils.OptReadInt((XmlNode)Page.GetDataItem(),"@width",20) %>'

                   />

            </asp:PlaceHolder>
            <asp:PlaceHolder ID="att_adder" runat="server">
               <asp:CheckBox ID="settingsAttAdder" Text='<%# XPath("@lbl") %>' runat="server"
                             Checked='<%# ((XmlElement)SettingsNode.SelectSingleNode(XPath("@xpath").ToString())).HasAttribute(XPath("@att").ToString()) %>'
                />
            </asp:PlaceHolder>
      </ItemTemplate>
  </asp:Repeater>

注:さらに簡単にするために、PlaceHolder コントロールを追加して物事をグループ化し、どのコントロールを削除するかを簡単に決定できるようにしました。

コードビハインド

次のコードは、すべてのリピーター アイテムが型であるという概念に基づいて構築されています。タイプは構成 xml から抽出されます。私の特定のシナリオでは、ID を使用してその型を単一のコントロールにすることができました。これは、必要に応じて簡単に変更できます。

 protected List<string> repeaterItemTypes
   {
      get
      {
         List<string> ret = (List<string>)ViewState["repeaterItemTypes"];
         if (ret == null)
         {
            ret = new List<string>();
            ViewState["repeaterItemTypes"] = ret;
         }
         return ret;
      }
   }

   protected void settingRepeater_ItemCreated(object sender, RepeaterItemEventArgs e)
   {
      string type;
      if (e.Item.DataItem != null)
      {
         // data binding mode..
         type = ((XmlNode)e.Item.DataItem).LocalName;
         int i = e.Item.ItemIndex;
         if (i == repeaterItemTypes.Count)
            repeaterItemTypes.Add(type);
         else
            repeaterItemTypes.Insert(e.Item.ItemIndex, type);
      }
      else
      {
         // restoring from ViewState
         type = repeaterItemTypes[e.Item.ItemIndex];
      }

      for (int i = e.Item.Controls.Count - 1; i >= 0; i--)
      {
         if (e.Item.Controls[i].ID != type) e.Item.Controls.RemoveAt(i);
      }
   }
于 2008-11-09T22:35:47.897 に答える
1

次のようなものが必要です。

<ItemTemplate>
    <%# GetContent(Page.GetDataItem()) %>
</ItemTemplate>

そして、コード ビハインドですべてのコントロールを生成します。

于 2008-11-08T02:30:53.070 に答える